// var createError = require('http-errors');
// var bodyParser = require('body-parser');
// var formidable = require('formidable');
var cookieParser = require('cookie-parser');
var express = require('express');
var logger = require('morgan');
var http = require('http');
var path = require('path');
var fs = require('fs');
var config = require('./config')
const cors = require('cors');
const nodemailer = require("nodemailer");



//引用数据库模块
var db_util = require('./db_utility');
var xlsx = require('node-xlsx');
// const { setUncaughtExceptionCaptureCallback, off, abort } = require('process');


function skipLog(req) {
  return req.method == 'POST' || req.method == 'OPTIONS';
}


var app = express();

app.use(logger('dev', { skip: skipLog }));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(express.json({ limit: '150mb' }));
app.use(express.urlencoded({ limit: '150mb', extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));


//设置跨域访问
app.all('*', function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
  res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
  res.header("X-Powered-By", ' 3.2.1');
  res.header("Content-Type", "application/json;charset=utf-8");
  next();
});

var g_cncOeeMonthBusy = false;
var g_nWaitTime = 180 * 1000; // 最大等待时间
var g_nOffTime = 600 * 1000;  // 最小关机时间间隔
var g_lastUpdateTime = 0; // 上一次数据更新时间，如果超过3分钟没有更新就认为关机了。
var g_userInfo = new Array();

//FSMS
app.post('/Login', async (req, res) => {
  console.log('Login from ' + req.ip);
  let body = req.body;
  try {
    let sql = "select * from employee where job_no = '" + body.name + "'";
    let suc = await db_util.query(sql);
    let json = {};
    let date = new Date();
    let date2 = getMonthDayTime(date, 1, 1);
    if (suc.length > 0) {
      if (suc[0].password == body.password) {
        json["result"] = "ok";
        json["name"] = suc[0].name;
        json["name_PY"] = suc[0].name_PY;
        json["job_no"] = suc[0].job_no;
        json["department"] = suc[0].department;
        json["department_abb"] = suc[0].department_abb;
        json["role"] = suc[0].role;
        json["level"] = suc[0].level;
        json["remark"] = suc[0].remark;

        let insert = true;
        for (let i = 0; i < g_userInfo.length; i++) {
          if (g_userInfo[i]['job_no'] == json["job_no"]) {
            console.log('上一次登录地址：' + g_userInfo[i]["ip"]);
            insert = false;
            g_userInfo[i]["name"] = suc[0].name;
            g_userInfo[i]["job_no"] = suc[0].job_no;
            g_userInfo[i]["level"] = suc[0].level;
            g_userInfo[i]["ip"] = req.ip;
            g_userInfo[i]["role"] = suc[0].role;
            g_userInfo[i]["remark"] = suc[0].remark;
            g_userInfo[i]["loginTime"] = date2;
            console.log(g_userInfo[i]);
            break;
          }
        }
        if (insert == true) {
          let msg = {};
          msg["name"] = suc[0].name;
          msg["job_no"] = suc[0].job_no;
          msg["level"] = suc[0].level;
          msg["ip"] = req.ip;
          msg["role"] = suc[0].role;
          msg["remark"] = suc[0].remark;
          msg["loginTime"] = date2;
          g_userInfo.push(msg);
          console.log(msg);
        }

        sql = "insert into workhour values(null, '" + suc[0].job_no + "', '" + req.ip + "', '" + date2 + "', '登录成功', '')";
      } else {
        json["result"] = "error";
        json["description"] = "password error";
        console.log(body.name + '登录，但密码错误');
        sql = "insert into workhour values(null, '" + suc[0].job_no + "', '" + req.ip + "', '" + date2 + "', '密码错误', '')";
      }
    } else {
      json["result"] = "error";
      json["description"] = "not found the job_no " + body.name;
      console.log(json);
      sql = "insert into workhour values(null, '" + body.name + "', '" + req.ip + "', '" + date2 + "', '工号不存在', '')";
    }
    await db_util.query(sql);
    res.status(200);
    res.json(json);
  } catch (error) {
    console.log(error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/unLogin', function (req, res) {
  for (var i = 0; i < g_userInfo.length; i++) {
    if (g_userInfo[i]['ip'] == req.ip) {
      console.log(req.ip + ' ' + g_userInfo[i]["name"] + " 已注销");
      g_userInfo.splice(i, 1);
      break;
    }
  }
  res.status(200);
  res.json({ "result": "ok" });
})


function CheckUserInfo(req) {
  var i = 0;
  var json = {};
  if (req.body.job_no != undefined) {
    for (i = 0; i < g_userInfo.length; i++) {
      if (g_userInfo[i]['job_no'] == req.body.job_no) {
        json["name"] = g_userInfo[i]["name"];
        json["job_no"] = g_userInfo[i]["job_no"];
        json["remark"] = g_userInfo[i]["remark"];
        json["isManager"] = g_userInfo[i]["remark"].includes('部門主管');
        break;
      }
    }
  } else {
    i = g_userInfo.length;
    json["isManager"] = true; // 不设置工号就默认有主管权限
  }
  if (i == g_userInfo.length) {
    for (i = 0; i < g_userInfo.length; i++) {
      if (g_userInfo[i]['ip'] == req.ip) {
        json["name"] = g_userInfo[i]["name"];
        json["job_no"] = g_userInfo[i]["job_no"];
        break;
      }
    }
  }
  return json;
}

//NOUSE
app.post('/CheckUserPassword', function (req, res) {
  var body = req.body;
  var sql = "select * from employee where job_no = '" + body.name + "'";
  db_util.ExecuteSQL(sql, null,
    (sucData) => {
      if (sucData.length > 0) {
        if (sucData[0].password == body.password) {
          res.status(200);
          res.json({ "result": "ok" });
        } else {
          res.status(200);
          res.json({ "result": "error", "errorCode": "1", "description": "the password is wrong" });
        }
      } else {
        res.status(200);
        res.json({ "result": "error", "errorCode": "2", "description": "not found the job_no" });
      }
    },
    (errData) => {
      res.status(200);
      res.json({ "result": "error", "errorCode": "3", "description": errData.message });
      console.log(errData.message);
    }
  );
})

//FSMS
app.post('/QueryUser', function (req, res) {
  var body = req.body;
  var sql = "select name, name_PY, job_no, department, department_abb, role, level, password, remark, wechat, mail, mobile from employee";
  if (body.level != undefined) {
    if (body.level.length > 0)
      sql += " where level = " + body.level + "";
  }
  db_util.ExecuteSQL(sql, null,
    (sucData) => {
      var json = {};
      var array = new Array();
      if (sucData.length > 0) {
        var go = 0;
        var filter = "";
        if (body.filter != undefined)
          filter = body.filter;
        var filter2 = "";
        if (body.filter2 != undefined)
          filter2 = body.filter2;
        sucData.forEach(element => {
          go = 0;
          if (filter.length > 0 || filter2.length > 0) {
            if (filter.length > 0) {
              if (element.remark.indexOf(filter) >= 0)
                go += 1;
            }
            if (filter2.length > 0) {
              if (element.remark.indexOf(filter2) >= 0)
                go += 1;
            }
          } else {
            go = 2;
          }
          if (go > 0)
            array.push(element);
        });
      }
      json["result"] = "ok";
      json["order"] = array;
      res.status(200);
      res.json(json);
      //console.log('query users: ' + array.length);
    },
    (errData) => {
      console.log(errData.message);
      res.status(200);
      json["result"] = "error";
      json["errorCode"] = "1";
      json["description"] = errData.message;
      res.json(json);
    }
  );
})

//FSMS
app.post('/AddUser', function (req, res) {
  var body = req.body;
  var sql = "select * from employee where job_no = '" + body.job_no + "'";
  db_util.ExecuteSQL(sql, null,
    (sucData) => {
      if (sucData.length > 0) {
        res.status(200);
        res.json({ "result": "error", "errorCode": "1", "description": "the job_no exists already" });
      } else {
        var wechat = body.wechat;
        if (wechat == null)
          wechat = "";
        sql = "insert into employee (name, name_PY, job_no, department, department_abb, role, level, password, remark, wechat, mail, mobile) values('" + body.name + "', '" + body.name_PY + "', '" + body.job_no + "', '" + body.department + "', '" + body.department_abb + "', '" + body.role + "', '" + body.level + "', '" + body.password + "', '" + body.remark + "', '" + wechat + "', '" + body.mail + "', '" + body.mobile + "')";
        db_util.ExecuteSQL(sql, null,
          (suc) => {
            res.status(200);
            res.json({ "result": "ok" });
          },
          (err) => {
            res.status(200);
            res.json({ "result": "error", "errorCode": "2", "description": err.message });
          }
        );
      }
    },
    (errData) => {
      res.status(200);
      res.json({ "result": "error", "errorCode": "3", "description": errData.message });
      console.log(errData.message);
    }
  );
})

//FSMS
app.post('/UpdateUser', function (req, res) {
  var body = req.body;
  var flag = false;
  var sql = "Update employee set ";
  if (body.job_no == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "the job_no is not found" });
    return;
  }
  if (body.name != undefined) {
    if (flag)
      sql += ", ";
    sql += "name = '" + body.name + "'";
    flag = true;
  }
  if (body.name_PY != undefined) {
    if (flag)
      sql += ", ";
    sql += "name_PY = '" + body.name_PY + "'";
    flag = true;
  }
  if (body.department != undefined) {
    if (flag)
      sql += ", ";
    sql += "department = '" + body.department + "'";
    flag = true;
  }
  if (body.department_abb != undefined) {
    if (flag)
      sql += ", ";
    sql += "department_abb = '" + body.department_abb + "'";
    flag = true;
  }
  if (body.role != undefined) {
    if (flag)
      sql += ", ";
    sql += "role = '" + body.role + "'";
    flag = true;
  }
  if (body.level != undefined) {
    if (flag)
      sql += ", ";
    sql += "level = " + body.level + "";
    flag = true;
  }
  if (body.password != undefined) {
    if (flag)
      sql += ", ";
    sql += "password = '" + body.password + "'";
    flag = true;
  }
  if (body.remark != undefined) {
    if (flag)
      sql += ", ";
    sql += "remark = '" + body.remark + "'";
    flag = true;
  }
  if (body.wechat != undefined) {
    if (flag)
      sql += ", ";
    sql += "wechat = '" + body.wechat + "'";
    flag = true;
  }
  if (body.mail != undefined) {
    if (flag)
      sql += ", ";
    sql += "mail = '" + body.mail + "'";
    flag = true;
  }
  if (body.mobile != undefined) {
    if (flag)
      sql += ", ";
    sql += "mobile = '" + body.mobile + "'";
    flag = true;
  }
  if (flag) {
    sql += " where job_no = '" + body.job_no + "'";
    db_util.ExecuteSQL(sql, null,
      (sucData) => {
        console.log(sucData.message);
        if (body.name != undefined) {
          sql = "update machining_engineer set name = '" + body.name + "' where job_no = '" + body.job_no + "'";
          db_util.ExecuteSQL(sql, null,
            (suc) => {
              res.status(200);
              if (sucData.affectedRows > 0)
                res.json({ "result": "ok", "changedRows": sucData.changedRows });
              else
                res.json({ "result": "error", "description": "not find the job_no" });
            },
            (err) => {
              res.status(200);
              if (sucData.affectedRows > 0)
                res.json({ "result": "ok", "changedRows": sucData.changedRows });
              else
                res.json({ "result": "error", "description": "not find the job_no" });
            }
          );
        } else {
          res.status(200);
          if (sucData.affectedRows > 0)
            res.json({ "result": "ok", "changedRows": sucData.changedRows });
          else
            res.json({ "result": "error", "description": "not find the job_no" });
        }
      },
      (errData) => {
        res.status(200);
        res.json({ "result": "error", "description": errData.message });
        console.log(sql);
      }
    );
  } else {
    res.status(200);
    res.json({ "result": "error", "description": "no column was matched to update" });
    console.log(sql);
  }
})

//FSMS
app.post('/DeleteUser', function (req, res) {
  var body = req.body;
  var sql = "delete from employee where job_no = '" + body.job_no + "'";
  console.log(sql);
  db_util.ExecuteSQL(sql, null,
    (sucData) => {
      res.status(200);
      if (sucData.affectedRows > 0)
        res.json({ "result": "ok" });
      else
        res.json({ "result": "error", "description": "not find the job_no" });
    },
    (errData) => {
      res.status(200);
      res.json({ "result": "error", "description": errData.message });
      console.log(errData.message);
    }
  );
})

//NOUSE
app.post('/AddWorkFile', function (req, res) {
  var body = req.body;
  var unionorder = body.unionorder;
  var workorder = body.workorder;
  var filepath = body.filepath;
  if (unionorder == null || workorder == null || filepath == null) {
    res.status(200);
    res.json({ "result": "error", "errorCode": "1", "description": "not found the matched column" });
    return;
  }
  var sql = "select * from machining_files where union_order = '" + unionorder + "' and sheet_order = '" + workorder + "'";
  if (unionorder != "kanban")
    sql += " and file_path = '" + filepath + "'";
  db_util.ExecuteSQL(sql, null,
    (suc) => {
      if (suc.length == 0) {
        sql = "insert into machining_files (union_order, sheet_order, file_path, file_name, upload_time, file_status) values('" + unionorder + "', '" + workorder + "', '" + filepath + "', '" + body.filename + "', '" + body.uploadtime + "', '" + body.filestatus + "')";
        db_util.ExecuteSQL(sql, null,
          (sucData) => {
            console.log(sql);
            res.status(200);
            res.json({ "result": "ok" });
          },
          (errData) => {
            res.status(200);
            res.json(errData.message);
          }
        );
      } else {
        if (unionorder == "kanban")
          sql = "update machining_files set file_path = '" + filepath + "', file_name = '" + body.filename + "', upload_time = '" + body.uploadtime + "' where union_order = '" + unionorder + "' and sheet_order = '" + workorder + "'";
        else
          sql = "update machining_files set file_name = '" + body.filename + "', upload_time = '" + body.uploadtime + "', file_status = '" + body.filestatus + "', remark = '" + body.remark + "' where union_order = '" + unionorder + "' and sheet_order = '" + workorder + "' and file_path = '" + filepath + "'";
        db_util.ExecuteSQL(sql, null,
          (suc2) => {
            res.status(200);
            res.json({ "result": "ok" });
          },
          (err2) => {
            res.status(200);
            res.json({ "result": "error", "errorCode": "2", "description": err2.message });
          }
        );
      }
    },
    (err) => {
      res.status(200),
        res.json({ "result": "error", "errorCode": "3", "description": err.message });
    }
  );
})

//FSMS
app.post('/UpdateWorkFile', async (req, res) => {
  let body = req.body;
  let sql = "Update machining_files set ";
  sql += body.name;
  sql += " = '" + body.newValue + "'";
  let parseFile = false;
  if (body.name2 != undefined && body.newValue2 != undefined) {
    sql += ", "
    sql += body.name2;
    sql += " = '" + body.newValue2 + "'";
    if (body.name2 == "file_status" && body.newValue2 == '1')
      parseFile = true;
  }
  sql += " where id = '" + body.id + "'";
  console.log(sql);
  try {
    await db_util.query(sql);
    if (body.name == "file_status" && body.newValue == '1') // 审核通过
      parseFile = true;
    if (parseFile == true) {
      sql = "select * from machining_files where id = '" + body.id + "'";
      let suc = await db_util.query(sql);
      let bomFile = suc[0].file_path;
      let i = bomFile.lastIndexOf('.');
      if (i > 1) {
        let ext = bomFile.substr(i + 1).toLowerCase();
        if (ext == 'pdf') {
          sql = "select id from machining_union_sheet where union_order = '" + suc[0]['union_order'] + "' and name = '" + suc[0]['sheet_order'] + "'";
          let succ2 = await db_util.query(sql);
          if (succ2.length > 0) {
            setTimeout(function () { ParsePdfFile(suc[0].union_order, bomFile); }, 1000);
            console.log('Prepare to parse: ' + bomFile);
          } else {
            console.log('审核通过PDF文件但不是工联单所需的', sql, bomFile);
          }
        } else if (ext == 'xlsx' || ext == 'xls') {
          sql = "select id from machining_union_sheet where union_order = '" + suc[0]['union_order'] + "' and name = '" + suc[0]['sheet_order'] + "'";
          let succ2 = await db_util.query(sql);
          if (succ2.length > 0) {
            setTimeout(function () { ParseBOMFile(bomFile); }, 1000);
            console.log('Prepare to parse: ' + bomFile);
          } else {
            console.log('审核通过Excel文件但不是工联单所需的', sql, bomFile);
          }
        } else if (ext == 'stp') {
          i = await ValidDesignFiles(suc[0].union_order);
        }
      }
    }
    if ((body.name == "file_status" && body.newValue == '2') || (body.name2 == "file_status" && body.newValue2 == '2')) {
      sql = "select * from machining_files where id = '" + body.id + "'";
      let suc2 = await db_util.query(sql);
      if (suc2[0].file_status == 2) {
        await ValidDesignFiles(suc2[0].union_order);
      }
    }
    res.status(200);
    res.json({ "result": "ok" });
  } catch (error) {
    console.log('UpdateWorkFile error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/DeleteWorkFile', function (req, res) {
  var sql = "select * from machining_files where id = '" + req.body.id + "'";
  console.log(sql);
  db_util.ExecuteSQL(sql, null,
    (sucData) => {
      if (sucData.length > 0) {
        var filePath = sucData[0].file_path;
        fs.unlink(filePath, function (err2) {
          if (err2) {
            console.log('Failed to delete the file: ' + filePath);
          } else {
            console.log('Succeeded to delete the file: ' + filePath);
          }
        })
        sql = "delete from machining_files where id = '" + req.body.id + "'";
        db_util.ExecuteSQL(sql, null,
          (suc) => {
            res.status(200);
            res.json({ "result": "ok" });
          },
          (err) => {
            res.status(200);
            res.json({ "result": "error", "description": "failed to delete the file" });
          }
        );
      } else {
        res.status(200);
        res.json({ "result": "error", "description": "not find the id" });
      }
    },
    (errData) => {
      res.status(200);
      res.json({ "result": "error", "description": errData.message });
      console.log(errData.message);
    }
  );
})

//FSMS
app.post('/QueryWorkFiles', async (req, res) => {
  let body = req.body;
  let unionorder = body.unionorder;
  let workorder = body.workorder;
  console.log('QueryWorkFiles body:', body);
  let array = new Array();
  try {
    let sql = "select id, imagefile from machining_sheet where quatity != '0' and union_order = '" + unionorder + "' and sheet_order = '" + workorder + "'";
    let suc = await db_util.query(sql);
    if (suc.length > 0) {
      if (suc[0]["imagefile"] != "") {
        let arr = suc[0]["imagefile"].split(",");
        for (let i = 0; i < arr.length; i++) {
          let json = {};
          json["id"] = "0";
          json["file_path"] = "./public/" + arr[i];
          let k = arr[i].lastIndexOf("/");
          json["file_name"] = arr[i].substr(k + 1);
          json["file_status"] = "1";
          json["upload_time"] = "";
          json["remark"] = "解析圖檔";
          array.push(json);
        }
      }
      /*sql = "select id, name from machining_union_sheet where union_order = '" + unionorder + "'";
      let succ2 = await db_util.query(sql);
      if( succ2.length > 0 )
      {
        workorder = succ2[0]["name"]; // 传过来的是sheet_order，在文件表中是查不到的
      }*/
    }
  } catch (error) {
    console.log('QueryWorkFiles: ', error);
  }
  try {
    let sql = "select id, file_path, file_name, file_status, upload_time, remark from machining_files where union_order = '" + unionorder + "' and sheet_order = '" + workorder + "'";
    let suc = await db_util.query(sql);
    let i = 0;
    let k = array.length;
    suc.forEach(element => {
      for (i = 0; i < k; i++) {
        if (element["file_path"] == array[i]["file_path"]) {
          array.splice(i, 1);
          k--;
          break;
        }
      }
      array.push(element);
    });
    res.status(200);
    res.json({ "result": "ok", "files": array });
    console.log('QueryWorkFiles result: ' + array.length);
  } catch (error) {
    console.log('QueryWorkFiles: ', error);
    res.status(200);
    res.json({ "result": "error", "description": "not found the user" })
  }
})

//FSMS
app.post('/QueryUnionOrder', async (req, res) => {
  let body = req.body;
  let json = {};
  let array = new Array();
  let stage = -1;
  let i = 0, j = 0, k = 0;
  console.log('QueryUnionOrder', body, 'from', req.ip);
  if (body.stage != undefined) {
    stage = parseInt(body.stage);
    if (isNaN(stage))
      stage = -1;
  }
  let sql = "";
  let sql2 = "select * from dispatch_sheet where rawdata != 0 and gjsl != '0'";
  if (body.cnc != undefined) {
    if (body.cnc.length > 0 && body.cnc != 'All')
      sql2 += " and cnc like '%" + body.cnc + "%'";
  }
  if (body.box != undefined && body.box != "") {
    sql2 += " and box like '%" + body.box + "%'";
  }
  let userInfo = CheckUserInfo(req);
  if (userInfo["isManager"] == false && stage == 4) // stage = 4：二次加工
  {
    sql2 += " and engineer_ercijiagong like '%" + userInfo["name"] + "%'";
    console.log(sql2);
  }
  try {
    sql = "select * from machining_union_sheet";
    if (body.stage == undefined && body.status == undefined) {
      let sucData = await db_util.query(sql);
      let succ2 = await db_util.query("select id, ToolWay from p79_tofsms");
      for (i = 0; i < sucData.length; i++) {
        if (sucData[i]['priority'] == '0')
          sucData[i]['priority'] = '';
        sucData[i]['pinjian_shijian'] = dotFixed(sucData[i]['pinjian_shijian'] / 3600.0);
        sucData[i]['toolway'] = "";
        if (sucData[i]['p79_id'] == '0')
          continue;
        for (k = 0; k < succ2.length; k++) {
          if (succ2[k]['id'] != sucData[i]['p79_id'])
            continue;
          if (succ2[k].ToolWay.indexOf("修改") >= 0) {
            sucData[i]['toolway'] = "維修";
            sucData[i]['code19'] = "/";
          } else if (succ2[k].ToolWay.indexOf("維修") >= 0) {
            sucData[i]['toolway'] = "維修";
            sucData[i]['code19'] = "/";
          } else {
            sucData[i]['toolway'] = succ2[k].ToolWay;
          }
          break;
        }
      }
      json["result"] = "ok";
      json["count"] = sucData.length;
      json["order"] = sucData;
      res.status(200);
      res.json(json);
      return;
    }
    if (body.status != undefined) // 0/进行中；1/已完成；2/取消；3/已指派；4/待审核；5/退回的工单
    {
      if (body.status == 0)
        sql += " where status = 0";
      else if (body.status == 1 || body.status == 2 || body.status == 3 || body.status == 4 || body.status == 5)
        sql += " where status = 12345"; // 已完成的记录在后面查询，在这里就要屏蔽
      else if (body.status == 10)
        sql += " where status = 0";
      else
        sql += " where status != 2";
    } else if (stage == 7) {
      sql += " where status = 1";
    } else {
      sql += " where status = 0";
    }
    if (userInfo["isManager"] == false && stage == 0) {
      sql += " and engineer like '%" + userInfo["name"] + "%'";
    }
    if (body.order != undefined && body.order != "") {
      sql += " and union_order like '%" + body.order + "%'";
    }
    if (body.name != undefined && body.name != "") {
      sql += " and name like '%" + body.name + "%'";
    }
    console.log(sql);
    sql += " order by delivery_date ASC"
    let sucData = await db_util.query(sql);
    //console.log('查询到的工单数目：' + sucData.length + ', status: ' + body.status);
    sql = "select * from machining_engineer";
    if (req.body.type != undefined)
      sql += " where type = '" + req.body.type + "'";
    else if (stage == 4)
      sql += " where type = 'engineer_ercijiagong'";
    else
      sql += " where type = 'engineer'";
    let suc1 = await db_util.query(sql);
    for (j = 0; j < sucData.length; j++) {
      sql = sql2 + " and union_order = '" + sucData[j].union_order + "'";
      if (stage > 0)
        sql += " and status = '" + stage + "'";
      let suc2 = await db_util.query(sql);
      if (suc2.length == 0 && stage > 0 && stage != 7)
        continue;
      // 先判断提示tip的值
      sucData[j].tip = "";
      // 先检查是否要设置new标记
      if (body.job_no != undefined) // 员工
      {
        if (sucData[j].other_remark != '') // 治具加工的退单备注
        {
          sucData[j].tip = "2";
        } else {
          sql = "select id from machining_files where union_order = '" + sucData[j].union_order + "' and file_status = 2";
          let succ3 = await db_util.query(sql);
          if (succ3.length >= db_util.config.file_number)
            sucData[j].tip = "2";
        }
      } else {
        sql = "select id from machining_files where union_order = '" + sucData[j].union_order + "' and file_status = 0";
        let succ4 = await db_util.query(sql);
        if (succ4.length >= db_util.config.file_number)
          sucData[j].tip = "2";
      }
      // 再检查是否有提醒标记，此标记优先
      if (stage == 1) // 编程
      {
        for (i = 0; i < suc2.length; i++) {
          if (suc2[i].end_date == '') // 加工期限
          {
            sucData[j].tip = "1";
            break;
          }
        }
        if (i == suc2.length) {
          for (i = 0; i < suc2.length; i++) {
            if (suc2[i].remark != '') // 退单备注
            {
              sucData[j].tip = "2";
              break;
            }
          }
        }
      } else if (stage == 2) // 加工
      {
        for (i = 0; i < suc2.length; i++) {
          if (suc2[i].end_date == '') {
            sucData[j].tip = "1";
            break;
          }
        }
        if (i == suc2.length) {
          for (i = 0; i < suc2.length; i++) {
            if (suc2[i].remark != '') {
              sucData[j].tip = "2";
              break;
            }
          }
        }
      } else if (stage == 3) // 品检
      {
        for (i = 0; i < suc2.length; i++) {
          if (suc2[i].check_date == '') // 送检日期
          {
            sucData[j].tip = "1";
            break;
          }
        }
        if (i == suc2.length) {
          for (i = 0; i < suc2.length; i++) {
            if (suc2[i].remark != '') {
              sucData[j].tip = "2";
              break;
            }
          }
        }
      } else if (stage == 4) // 二次加工
      {
        for (i = 0; i < suc2.length; i++) {
          if (suc2[i].machine_end_date_2 == '') // 二次加工期限
          {
            sucData[j].tip = "1";
            break;
          }
        }
        if (i == suc2.length) {
          for (i = 0; i < suc2.length; i++) {
            if (suc2[i].remark != '') {
              sucData[j].tip = "2";
              break;
            }
          }
        }
      }
      /*if( stage == 1 ) // 编程
      {
        for(i=0; i<suc2.length; i++)
        {
          if( suc2[i].cnc_name == '' )
          {
            break;
          }
        }
        if( i < suc2.length )
        {
          console.log(sucData[j].union_order + ', 编程状态为1但是没有设置机台号，略过');
          continue;
        }
      }*/
      // element.engineer的值需要从suc1中查找
      let engineer = "";
      for (i = 0; i < suc1.length; i++) {
        if (sucData[j].union_order == suc1[i].union_order) {
          if (engineer.length > 0)
            engineer += ","
          engineer += suc1[i].name;
        }
      }
      sucData[j].engineer = engineer;
      let haveJiagongjian = false; // 一些不满足要求的工联单就不要了
      if (engineer.length == 0) {
        haveJiagongjian = true;
      } else if (body.status != undefined) // 主管审核
      {
        haveJiagongjian = true;
      } else if (suc2.length == 0 && stage == 0) {
        haveJiagongjian = true;
      } else {
        for (k = 0; k < suc2.length; k++) {
          if (req.body.workstatus != undefined) {
            if (suc2[k].status != req.body.workstatus) // 只要有一条加工件的状态不符合要求，该工联单就不要了
              break;
          } else {
            haveJiagongjian = true;
            break;
          }
        }
      }
      if (haveJiagongjian == false) {
        if (body.stage == undefined && body.status == undefined) // 库房没有传入任何参数
        {
          sql = "select id from machining_sheet where quatity != '0' and union_order = '" + sucData[j].union_order + "'";
          let succ3 = await db_util.query(sql);
          if (succ3.length > 0)
            haveJiagongjian = true;
          else
            console.log(sucData[j].union_order, '大表中没有加工件或标准件');
        }
      }
      if (haveJiagongjian == false) {
        console.log('忽略：', sucData[j].union_order, stage, '有指派工程师，没有传入status参数，小表中加工件状态不对或没有加工件');
      }
      if (haveJiagongjian == true) // 检查治具状态：未入库/未领取/部分领取/已领取
      {
        if (req.body.warehouse != undefined) {
          if (req.body.warehouse == '0') // 查找未入库的工联单
          {
            if (sucData[j].ruku_time.length > 0)
              haveJiagongjian = false;
          } else if (req.body.warehouse == '1') // 查找未领取的工联单
          {
            let count = parseInt(sucData[j].lingqu_count);
            if (isNaN(count))
              count = 0;
            if (count > 0 || sucData[j].ruku_time.length == 0)
              haveJiagongjian = false;
          } else if (req.body.warehouse == '2') // 查找部分领取的工联单
          {
            let count = parseInt(sucData[j].lingqu_count);
            if (isNaN(count))
              count = 0;
            let quatity = parseInt(sucData[j].quatity);
            if (count == 0 || count == quatity)
              haveJiagongjian = false;
          } else if (req.body.warehouse == '3') // 查找已领取的工联单
          {
            let count = parseInt(sucData[j].lingqu_count);
            if (isNaN(count))
              count = 0;
            let quatity = parseInt(sucData[j].quatity);
            if (count < quatity)
              haveJiagongjian = false;
          }
        }
      }
      if (haveJiagongjian == true) // 检查阶段
      {
        if (stage >= 0) {
          if (sucData[j].stage.charAt(stage) != req.body.stageValue) {
            haveJiagongjian = false;
            //console.log(sucData[j].union_order + '，工单状态' + sucData[j].stage + '[' + stage + ']不等于' + req.body.stageValue + '，略过');
          }
        }
      }
      if (haveJiagongjian == true) {
        if (stage == 4) // 二次加工
        {
          for (k = 0; k < suc2.length; k++) {
            if (sucData[j].union_order == suc2[k].union_order) {
              break;
            }
          }
          if (k == suc2.length) {
            haveJiagongjian = false;
            console.log(sucData[j].union_order + '大表中没有二次加工信息，略过');
          }
        }
      }
      if (haveJiagongjian == true) {
        i = 0;
        if (sucData[j]['priority'] != '0')
          i++;
        for (k = 0; k < suc2.length; k++) {
          if (suc2[k]['timestamp'] != '')
            i++;
        }
        sucData[j]['timer_count'] = i;
        array.push(sucData[j]);
      }
    }

    sql2 = "";
    if (userInfo["isManager"] == false && stage == 0) {
      sql2 += " and engineer like '%" + userInfo["name"] + "%'";
    }
    if (body.order != undefined && body.order != "") {
      sql2 += " and union_order like '%" + body.order + "%'";
    }
    if (body.name != undefined && body.name != "") {
      sql2 += " and name like '%" + body.name + "%'";
    }
    if (body.status == 1) {
      sql = "select * from machining_union_sheet where status = 1 OR stage = '0000000100'" + sql2;
      sucData = await db_util.query(sql);
      sucData.forEach(element => {
        element["status"] = 1;
        element['timer_count'] = 0;
        array.push(element);
      });
    } else if (body.status == 2) {
      sql = "select * from machining_union_sheet where status = 2" + sql2;
      sucData = await db_util.query(sql);
      sucData.forEach(element => {
        element['timer_count'] = 0;
        array.push(element);
      });
    } else if (body.status == 3) // 已指派
    {
      sql = "select * from machining_union_sheet where status = 0 and engineer != '' and stage like '1_______%'" + sql2;
      sucData = await db_util.query(sql);
      for (let k = 0; k < sucData.length; k++) {
        let i = 0;
        if (sucData[k]['priority'] != '0')
          i++;
        sql = "select id, timestamp from dispatch_sheet where rawdata != 0 and gjsl != '0' and union_order = '" + sucData[k]['union_order'] + "' and timestamp != ''";
        let succ3 = await db_util.query(sql);
        i += succ3.length;
        sucData[k]['timer_count'] = i;
        array.push(sucData[k]);
      }
    } else if (body.status == 4) // 待审核
    {
      sql = "select union_order, sheet_order, file_status from machining_files where union_order != 'kanban' and union_order != 'warehouse'";
      let suc = await db_util.query(sql);
      sql = "select * from machining_union_sheet where status = 0 and stage like '1_______%'" + sql2;
      sucData = await db_util.query(sql);
      let k, run_time, total_time;
      sucData.forEach(element => {
        run_time = 0;
        total_time = 0;
        for (k = 0; k < suc.length; k++) {
          if (element['union_order'] == suc[k]['union_order'] && element['name'] == suc[k]['sheet_order']) {
            total_time++;
            if (suc[k]['file_status'] == 1) {
              run_time++;
            }
          }
        }
        if (total_time >= 3 /*&& run_time < total_time*/) // 只要有文件，不管文件是否审核
        {
          element['timer_count'] = 0;
          array.push(element);
        }
      });
    } else if (body.status == 5) // 退单
    {
      sql = "select * from machining_union_sheet where status = 0 and tuidan != '' and stage like '1_______%'" + sql2;
      sucData = await db_util.query(sql);
      for (let k = 0; k < sucData.length; k++) {
        let i = 0;
        if (sucData[k]['priority'] != '0')
          i++;
        sql = "select id, timestamp from dispatch_sheet where rawdata != 0 and gjsl != '0' and union_order = '" + sucData[k]['union_order'] + "' and timestamp != ''";
        let succ3 = await db_util.query(sql);
        i += succ3.length;
        sucData[k]['timer_count'] = i;
        array.push(sucData[k]);
      }
    }
    let succ2 = await db_util.query("select id, ToolWay from p79_tofsms");
    for (i = 0; i < array.length; i++) {
      if (array[i]['priority'] == '0')
        array[i]['priority'] = '';
      array[i]["pinjian_shijian"] = dotFixed(array[i]["pinjian_shijian"] / 3600.0);
      array[i]["toolway"] = "";
      if (array[i]["p79_id"] == '0')
        continue;
      for (k = 0; k < succ2.length; k++) {
        if (succ2[k]['id'] != array[i]['p79_id'])
          continue;
        if (succ2[k].ToolWay.indexOf("修改") >= 0) {
          array[i]["toolway"] = "維修";
          array[i]["code19"] = "/";
        } else if (succ2[k].ToolWay.indexOf("維修") >= 0) {
          array[i]["toolway"] = "維修";
          array[i]["code19"] = "/";
        } else {
          array[i]["toolway"] = succ2[k].ToolWay;
        }
        break;
      }
    }
    if (body.status != 2 && stage == 0 && userInfo["isManager"] == true) {
      sucData.length = 0;
      sql = "select union_order, name, status, engineer, stage, tuidan from machining_union_sheet where status != 2";
      sucData = await db_util.query(sql);
      let json2 = { 'status0': 0, 'status1': 0, 'status3': 0, 'status4': 0, 'status5': 0 };
      if (body.status == 4) {
        json2['status4'] = array.length;
      } else {
        sql = "select union_order, sheet_order, file_status from machining_files where union_order != 'kanban' and union_order != 'warehouse'";
        let suc = await db_util.query(sql);
        let i, k, run_time, total_time;
        for (i = 0; i < sucData.length; i++) {
          if (sucData[i]['status'] != 0)
            continue;
          if (sucData[i]['stage'].charAt(0) != 1)
            continue;
          run_time = 0;
          total_time = 0;
          for (k = 0; k < suc.length; k++) {
            if (sucData[i]['union_order'] == suc[k]['union_order'] && sucData[i]['name'] == suc[k]['sheet_order']) {
              total_time++;
              if (suc[k]['file_status'] == 1) {
                run_time++;
              }
            }
          }
          if (total_time >= 3 /*&& run_time < total_time*/) // 只要有文件，不管文件是否审核
          {
            json2['status4']++;
          }
        }
      }
      for (let i = 0; i < sucData.length; i++) {
        if (sucData[i]['status'] == 1 || sucData[i]['stage'] == '0000000100') {
          json2['status1']++;
        }
      }
      for (let i = sucData.length - 1; i >= 0; i--) {
        if (sucData[i].stage.charAt(stage) != req.body.stageValue) {
          sucData.splice(i, 1);
        }
      }
      for (let i = 0; i < sucData.length; i++) {
        if (sucData[i]['status'] != 0)
          continue;
        json2['status0']++;
        if (sucData[i]['engineer'] != '') {
          json2['status3']++;
        }
        if (sucData[i]['tuidan'] != '') {
          json2['status5']++;
        }
      }
      json['status_count'] = json2;
    }

    json["result"] = "ok";
    json["count"] = array.length;
    json["order"] = array;
    res.status(200);
    res.json(json);
    //console.log('get result: ' + array.length);
  } catch (error) {
    console.log('QueryUnionOrder failed, ' + error.message);
    res.status(200);
    json["result"] = "error";
    json["order"] = array;
    json["description"] = error.message;
    res.json(json);
  }
})

// 下面是组装查询，也可以总检，参数是stage:6/stageValue:1/status:6  FSMS
app.post('/QueryUnionOrderByStatusStage', async (req, res) => {
  let body = req.body;
  let json = {};
  let array = new Array();
  let sql = "select union_order, status, timestamp from dispatch_sheet where gjsl != '0' and rawdata != 0";
  let userInfo = CheckUserInfo(req);
  try {
    // 通过传过来的body来设置stage、status
    let index = 0;
    if (body.stage != undefined) {
      index = parseInt(body.stage);
      if (isNaN(index))
        index = 5;
    }
    let status = 5;
    if (body.status != undefined) {
      status = parseInt(body.status);
      if (isNaN(status))
        status = 5;
    }
    let suc2 = await db_util.query(sql);
    // 根据人员信息查找machining_union_sheet表数据：sucData，并重新设置一下里面的一下栏位tip、timer_count
    sql = "select * from machining_union_sheet where status = 0";
    if (userInfo["isManager"] == false && index == 5) {
      sql += " and engineer_zuzhuang like '%" + userInfo["name"] + "%'";
    }
    sql += " ORDER by delivery_date ASC";
    console.log('QueryUnionOrderByStatusStage', body, req.ip, sql);
    let sucData = await db_util.query(sql);
    //if( suc2.length > 0 ) // 2021-11-04，没有加工件也可以的
    {
      for (let k = 0; k < sucData.length; k++) {
        sucData[k].tip = "";
        if (sucData[k].assemble_remark != '')
          sucData[k].tip = "2";
        sucData[k]['timer_count'] = 0;
        if (sucData[k]['priority'] != '0')
          sucData[k]['timer_count']++;
      }
    }
    sql = "select * from machining_engineer where type = 'engineer_zuzhuang'";
    let suc1 = await db_util.query(sql);
    for (let j = 0; j < sucData.length; j++) {
      if (req.body.stage != undefined) {
        if (sucData[j].stage.charAt(index) != '1')
          continue;
      }
      let flag = false;
      for (let i = 0; i < suc2.length; i++) {
        if (suc2[i].union_order != sucData[j].union_order)
          continue;
        if (suc2[i].status != status) {
          flag = true;
          break;
        }
        if (suc2[i]['timestamp'] != '')
          sucData[j]['timer_count']++;
      }
      if (flag == true) // 只查所有工件全部为指定状态的工单
        continue;

      // element.engineer的值需要从suc1中查找
      let engineer = "";
      for (let i = 0; i < suc1.length; i++) {
        if (sucData[j].union_order == suc1[i].union_order) {
          if (engineer.length > 0)
            engineer += ","
          engineer += suc1[i].name;
        }
      }
      sucData[j].engineer = engineer;

      array.push(sucData[j]);
    }
    // 主管加入已完成的记录
    if (body.job_no == undefined) {
      sql = "select * from machining_union_sheet where status = 1 OR stage = '0000000100'";
      sucData = await db_util.query(sql);
      sucData.forEach(element => {
        element["status"] = 1;
        element['timer_count'] = 0;
        array.push(element);
      });
    }
    for (let i = 0; i < array.length; i++) {
      if (array[i]['priority'] == '0')
        array[i]['priority'] == '';
      if (array[i]["p79_id"] == '0')
        continue;
      sql = "select ToolWay from p79_tofsms where id = '" + array[i]["p79_id"] + "'";
      let succ2 = await db_util.query(sql);
      if (succ2.length > 0)
        array[i]["toolway"] = succ2[0]["ToolWay"];
    }

    json["result"] = "ok";
    json["count"] = array.length;
    json["order"] = array;
    res.status(200);
    res.json(json);
    //console.log('get result: ' + array.length);
  }
  catch (error) {
    console.log('QueryUnionOrder failed, ' + error.message);
    res.status(200);
    json["result"] = "error";
    json["order"] = array;
    json["errorCode"] = "2";
    json["description"] = error.message;
    res.json(json);
  }
})

//FSMS
app.post('/QueryWorkOrder', async (req, res) => {
  let body = req.body;
  let sql = "select * from machining_sheet where quatity != '0' and union_order = '" + body.unionorder + "'";
  if (body.type != undefined) {
    sql += " and type_flag = '" + body.type + "'";
  }
  let username = "";
  if (body.status != undefined) {
    if (body.status == '4') // 二次加工，必须匹配指定的二次加工工程师
    {
      let userInfo = CheckUserInfo(req);
      if (userInfo["isManager"] == false) {
        username = userInfo["name"];
      }
    }
  }
  let check_banci = false;
  if (body.banci != undefined) {
    if (body.banci.length > 0)
      check_banci = true;
  }
  console.log('QueryWorkOrder', body);
  try {
    let array = new Array();
    if (body.id != undefined) {
      sql = "select * from dispatch_sheet where id = '" + body.id + "'";
      let succ2 = await db_util.query(sql);
      if (succ2.length > 0) {
        sql = "select * from machining_sheet where quatity != '0' and union_order = '" + succ2[0]["union_order"] + "' and sheet_order = '" + succ2[0]["ljmc"] + "'";
        let suc = await db_util.query(sql);
        sql = "select bypass from machining_union_sheet where union_order = '" + succ2[0]["union_order"] + "'";
        let succ4 = await db_util.query(sql);
        for (let i = 0; i < suc.length; i++) {
          suc[i]["id"] = body.id;
          suc[i]["machine_remark"] = succ2[0]["machine_remark"];
          suc[i]["machine_remark_2"] = succ2[0]["machine_remark_2"];
          suc[i]["chaidan"] = 0;
          suc[i]["kg"] = false;
          suc[i]["bypass"] = "";
          if (succ4.length > 0)
            suc[i]["bypass"] = succ4[0]["bypass"];
          array.push(suc[i]);
        }
        console.log(body.id + ', ' + sql);
      }
      res.status(200);
      res.json({ "result": "ok", "order": array });
      return;
    }
    let suc = await db_util.query(sql);
    let bypass = "";
    sql = "select bypass from machining_union_sheet where union_order = '" + body.unionorder + "'";
    let succ4 = await db_util.query(sql);
    if (succ4.length > 0)
      bypass = succ4[0]["bypass"];
    if (body.type != undefined) {
      if (body.type == '0') {
        for (let i = 0; i < suc.length; i++) {
          suc[i]["chaidan"] = 0;
          suc[i]["kg"] = false;
          suc[i]["bypass"] = bypass;
          array.push(suc[i]);
        }
        res.status(200);
        res.json({ "result": "ok", "order": array, "jiagongjian": 0 });
        return;
      }
    }
    for (let i = 0; i < suc.length; i++) {
      if (suc[i].type_flag == '0') // 标准件在小表中是找不到的
      {
        if (body.status == '5') {
          if (body.box != undefined) {
            if (suc[i].box.indexOf(body.box) < 0)
              continue;
          }
          suc[i]["chaidan"] = 0;
          suc[i]["kg"] = false;
          suc[i]["bypass"] = bypass;
          array.push(suc[i]);
        }
        continue;
      }
      sql = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and ljmc = '" + suc[i].sheet_order + "'";
      if (body.cnc != undefined) {
        if (body.cnc.length > 0 && body.cnc != 'All') {
          sql += " and cnc like '%" + body.cnc + "%'";
        }
      }
      if (username != '')
        sql += " and engineer_ercijiagong like '%" + username + "%'";
      if (body.status != undefined)
        sql += " and status = '" + body.status + "'";
      if (check_banci)
        sql += " and banci = '" + body.banci + "'";
      if (body.box != undefined)
        sql += " and box like '%" + body.box + "%'";
      sql += "  and rawdata != 0 ORDER BY id ASC";
      let suc2 = await db_util.query(sql);
      if (suc2.length == 0)
        continue;

      suc[i]["status"] = suc2[0].status;
      suc[i]["remark"] = "";
      suc[i]["id"] = suc2[0].id;
      suc[i]["id2"] = suc2[0].id;
      for (let k = 0; k < suc2.length; k++) {
        if (suc2[k].remark == '')
          continue;
        if (suc[i]["remark"] != "")
          suc[i]["remark"] += ";";
        suc[i]["remark"] += suc2[k].remark;
      }
      suc[i]["box"] = suc2[0].box;
      suc[i]["cnc_name"] = suc2[0].cnc;
      suc[i]["banci"] = suc2[0].banci;
      suc[i]["jiagongriqi"] = suc2[0].jiagongriqi;
      suc[i]["end_date"] = suc2[0].end_date;
      suc[i]["speed_time"] = suc2[0].speed_time;
      suc[i]["estimate_time"] = suc2[0].estimate_time;
      suc[i]["machine_remark"] = suc2[0].machine_remark;
      suc[i]["check_status"] = suc2[0].check_status;
      suc[i]["check_date"] = suc2[0].check_date;
      suc[i]["check_remark"] = suc2[0].pinjian_bzhu;
      suc[i]["machine_end_date_2"] = suc2[0].machine_end_date_2;
      suc[i]["machine_time_2"] = suc2[0].machine_time_2;
      suc[i]["machine_remark_2"] = suc2[0].machine_remark_2;
      suc[i]["engineer_ercijiagong"] = suc2[0].engineer_ercijiagong;
      let temp = parseInt(suc[i]["pinjian_shijian"]);
      if (isNaN(temp))
        temp = 0;
      suc[i]["pinjian_shijian"] = dotFixed(temp / 3600.0);

      if (suc[i].bom_remark != 'V')
        suc[i].bom_remark = '';
      suc[i]["chaidan"] = 0;
      let quatity_total = parseInt(suc[i].quatity_total);
      if (quatity_total > 1) {
        sql = "select id from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and ljmc = '" + suc[i].sheet_order + "' and rawdata = 2";
        //if( body.status != undefined )
        //  sql += " and status = '"+ body.status +"'";
        let suc3 = await db_util.query(sql);
        if (suc3.length > 0)
          suc[i]["chaidan"] = 1;
      }
      suc[i]["kg"] = false;
      suc[i]["unionorder"] = suc2[0].union_order;
      suc[i]["workorder"] = suc2[0].ljmc;
      suc[i]["bypass"] = bypass;
      suc[i]['timestamp'] = suc2[0]['timestamp'];
      array.push(suc[i]);
    }
    //sql = "select * from machining_sheet where union_order = '"+ body.unionorder +"' and type_flag = '1'";
    sql = "select id from dispatch_sheet where gjsl != '0' and union_order = '" + body.unionorder + "' and rawdata != 0";
    let suc4 = await db_util.query(sql);

    res.status(200);
    res.json({ "result": "ok", "order": array, "jiagongjian": suc4.length });
  }
  catch (error) {
    console.log('QueryWOrkOrder exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
    return;
  }
})

//FSMS
app.post('/AddWorkTime', async (req, res) => {
  let body = req.body;
  console.log('AddWorkTime', body);
  let sql = "select * from machining_union_sheet where union_order = '" + body.unionorder + "'";
  try {
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      console.log('AddWorkTime error, not find the order: ' + body.unionorder);
      res.status(200);
      res.json({ "result": "error", "description": "not find the order" });
      return;
    }
    if (body.starttime != undefined) // 改到UpdateWorkOrder中去了
    {
      if (body.stage == '0' || body.stage == '5' || body.stage == '6') // 设计、组装、总检
      {
        let i = parseInt(body.starttime);
        if (isNaN(i)) {
          console.log('starttime is invalid');
          res.status(200);
          res.json({ "result": "error", "description": "starttime is invalid" });
          return;
        }
        i = parseInt(i / 1000);
        sql = "update machining_union_sheet set priority = " + i + " where union_order = '" + body.unionorder + "'";
        await db_util.query(sql);
      }
      else {
        if (body.id == undefined) {
          res.status(200);
          res.json({ "result": "error", "description": "没有传入小表的id值" });
          return;
        }
        sql = "update dispatch_sheet set timestamp = '" + body.starttime + "' where id = '" + body.id + "'";
        await db_util.query(sql);
      }
      res.status(200);
      res.json({ "result": "ok" });
      return;
    }
    let t = parseInt(suc[0].total_time);
    if (isNaN(t))
      t = 0;
    let t2 = 0;
    if (body.endtime != undefined) {
      let i = parseInt(body.endtime);
      if (isNaN(i)) {
        console.log('endtime is invalid');
        res.status(200);
        res.json({ "result": "error", "description": "endtime is invalid" });
        return;
      }
      i = parseInt(i / 1000);
      if (body.stage == '0' || body.stage == '5' || body.stage == '6') // 设计、组装、总检
      {
        sql = "select priority from machining_union_sheet where union_order = '" + body.unionorder + "'";
        let succ2 = await db_util.query(sql);
        if (succ2.length > 0) {
          let k = parseInt(succ2[0]["priority"]);
          if (isNaN(k)) {
            console.log('priority is invalid', sql);
          }
          else {
            t2 = i - k;
            if (t2 > 864000) // 超过10天
            {
              console.log('两个时间戳相差太大了：' + i + ' ~ ' + k);
              res.status(200);
              res.json({ "result": "error", "description": "两个时间戳相差太大了（没有设置开始时间吧）" });
              return;
            }
          }
        }
        else {
          console.log('Not find the union_order', sql);
        }
      }
      else {
        if (body.id == undefined) {
          res.status(200);
          res.json({ "result": "error", "description": "没有传入小表的id值" });
          return;
        }
        sql = "select timestamp from dispatch_sheet where id = '" + body.id + "'";
        let succ2 = await db_util.query(sql);
        if (succ2.length > 0) {
          let k = parseInt(succ2[0]["timestamp"]);
          if (isNaN(k)) {
            console.log('timestamp is null perhaps', succ2[0]["timestamp"]);
          }
          else {
            k = parseInt(k / 1000);
            t2 = i - k;
            if (t2 > 864000) // 超过10天
            {
              console.log('两个时间戳相差太大了：' + i + ' ~ ' + k);
              res.status(200);
              res.json({ "result": "error", "description": "两个时间戳相差太大了（没有设置开始时间吧）" });
              return;
            }
          }
        }
        else {
          console.log('Not find the id', sql);
        }
      }
      if (t2 > 0) {
        sql = "update dispatch_sheet set timestamp = '' where id = '" + body.id + "'";
        await db_util.query(sql);
      }
      else {
        console.log('t2 is 0');
      }
    }
    else if (body.time != undefined) {
      let index = body.time.indexOf(':');
      if (index > 0) {
        sql = body.time.substr(0, index);
        t2 = parseInt(sql);
        let offset = index + 1;
        index = body.time.indexOf(':', offset);
        if (index > 0) {
          t2 *= 3600;
          sql = body.time.substr(offset, index - offset);
          t2 += parseInt(sql) * 60;
          sql = body.time.substr(index + 1);
          t2 += parseInt(sql);
        }
        else {
          t2 *= 60;
          sql = body.time.substr(offset);
          t2 += parseInt(sql);
        }
      }
      else {
        t2 = parseInt(body.time);
      }
      if (isNaN(t2)) {
        t2 = 0;
      }
    }
    if (t2 == 0) {
      res.status(200);
      res.json({ "result": "error", "description": "time is null" });
      return;
    }

    t += t2;
    let t3 = 0;
    if (body.stage == '0')
      t3 = parseInt(suc[0].sheji_shijian);
    else if (body.stage == '1')
      t3 = parseInt(suc[0].biancheng_shijian);
    else if (body.stage == '2')
      t3 = parseInt(suc[0].jiagong_shijian);
    else if (body.stage == '3')
      t3 = parseInt(suc[0].pinjian_shijian);
    else if (body.stage == '4')
      t3 = parseInt(suc[0].ercijiagong_shijian);
    else if (body.stage == '5')
      t3 = parseInt(suc[0].zuzhuang_shijian);
    else if (body.stage == '6')
      t3 = parseInt(suc[0].zongjian_shijian);
    if (isNaN(t3))
      t3 = 0;
    t3 += t2;
    sql = "Update machining_union_sheet set total_time = '" + t + "'";
    if (body.stage == '0')
      sql += ", sheji_shijian = '" + t3 + "', priority = 0";
    else if (body.stage == '1')
      sql += ", biancheng_shijian = '" + t3 + "'";
    else if (body.stage == '2')
      sql += ", jiagong_shijian = '" + t3 + "'";
    else if (body.stage == '3')
      sql += ", pinjian_shijian = '" + t3 + "'";
    else if (body.stage == '4')
      sql += ", ercijiagong_shijian = '" + t3 + "'";
    else if (body.stage == '5')
      sql += ", zuzhuang_shijian = '" + t3 + "', priority = 0";
    else if (body.stage == '6')
      sql += ", zongjian_shijian = '" + t3 + "', priority = 0";
    sql += " where union_order = '" + body.unionorder + "'";
    await db_util.query(sql);
    console.log('Succeeded: ' + sql);

    if (body.stage == '3') {
      sql = "select * from machining_sheet where quatity != '0' and union_order='" + body.unionorder + "' and sheet_order = '" + body.ljmc + "'";
      let succ2 = await db_util.query(sql);
      if (succ2.length > 0) {
        t3 = parseInt(succ2[0].pinjian_shijian);
        if (isNaN(t3))
          t3 = 0;
        t3 += t2;
        sql = "update machining_sheet set pinjian_shijian = '" + t3 + "' where id = '" + succ2[0].id + "'";
        await db_util.query(sql);
        console.log('Succeeded: ' + sql);
      }
      else
        console.log('Failed to addworktime to machining_sheet: ' + sql);
    }

    t = 0;
    sql = "select id, priority from machining_union_sheet where union_order = '" + body.unionorder + "' and priority != 0";
    let succ3 = await db_util.query(sql);
    sql = "select id, timestamp from dispatch_sheet where rawdata != 0 and gjsl != '0' and union_order = '" + body.unionorder + "' and timestamp != ''";
    let succ4 = await db_util.query(sql);
    t = succ3.length + succ4.length;

    res.status(200);
    res.json({ "result": "ok", "timer_count": t });
  }
  catch (error) {
    console.log('AddWorkTime error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/AddUnionOrder', async (req, res) => {
  let body = req.body;
  console.log('AddUnionOrder', body);
  if (body.union_order == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "union_order is null" });
    return;
  }
  let sql = "select * from machining_union_sheet where union_order = '" + body.union_order + "'";
  try {
    let suc = await db_util.query(sql);
    if (suc.length > 0) {
      console.log('AddUnionOrder 出错，该工联单已存在：' + body.union_order);
      res.status(200);
      res.json({ "result": "error", "description": "该工联单已存在" });
      return;
    }
    let col = 'union_order';
    let val = '\'' + body.union_order + '\'';
    let temp = "name,quatity,delivery_date,apply_person,applyDeptPIC,charge_department,delivery_addr,factory,machine_type";
    let arr = temp.split(',');
    for (let i = 0; i < arr.length; i++) {
      temp = arr[i];
      if (body[temp] == undefined)
        continue;
      col += ', ';
      val += ', ';
      col += temp;
      val += '\'';
      val += body[temp];
      val += '\'';
    }
    sql = "insert into machining_union_sheet (" + col + ") values (" + val + ")";
    let succ2 = await db_util.query(sql);
    console.log('AddUnionOrder succeeded, id = ' + succ2.insertId);

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('AddUnionOrder error: ' + error.message);
    console.log(sql);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/UpdateUnionOrder', function (req, res) {
  var body = req.body;
  var sql = "Update machining_union_sheet set ";
  sql += body.name;
  sql += " = '" + body.newValue + "' where union_order='" + body.unionorder + "'";
  if (body.name == "code19") {
    if (body.newValue.length >= 19) {
      var code1 = body.newValue.substr(0, 19);
      var code2 = code1.substr(0, 16);
      var sql2 = "select union_order, code19 from machining_union_sheet where code19 like '" + code2 + "%' order by id desc";
      db_util.ExecuteSQL(sql2, null,
        (suc1) => {
          var ok = true;
          var code3 = "";
          var order = "";
          for (var i = 0; i < suc1.length; i++) {
            if (suc1[i].union_order == body.unionorder)
              continue;
            order = suc1[i].union_order;
            code3 = suc1[i].code19.substr(0, 19);
            if (suc1[i].code19.length > 38)
              code3 = suc1[i].code19.substr(20);
            if (code1 <= code3) {
              ok = false;
              break;
            }
          }
          if (ok == false) {
            console.log('Update code19 error, ' + order + ': ' + code3 + ' is bigger than ' + code1);
            res.status(200);
            res.json({ "result": "error", "description": "", "code19": code3 });
            return;
          }
          else {
            console.log(sql);
            db_util.ExecuteSQL(sql, null,
              (sucData) => {
                //console.log(sucData.message);
                res.status(200);
                res.json({ "result": "ok", "description": sucData.message });
              },
              (errData) => {
                res.status(200);
                res.json({ "result": "error", "errorCode": "1", "description": errData.message });
                console.log(sql);
              }
            );
          }
        },
        (err1) => {
          console.log('query code19 failed, ' + err1.message);
          console.log(sql);
          db_util.ExecuteSQL(sql, null,
            (sucData) => {
              //console.log(sucData.message);
              res.status(200);
              res.json({ "result": "ok", "description": sucData.message });
            },
            (errData) => {
              res.status(200);
              res.json({ "result": "error", "errorCode": "1", "description": errData.message });
              console.log(sql);
            }
          );
        }
      );
    }
    else {
      console.log(sql);
      db_util.ExecuteSQL(sql, null,
        (sucData) => {
          //console.log(sucData.message);
          res.status(200);
          res.json({ "result": "ok", "description": sucData.message });
        },
        (errData) => {
          res.status(200);
          res.json({ "result": "error", "errorCode": "1", "description": errData.message });
          console.log(sql);
        }
      );
    }
  }
  else {
    console.log(sql);
    db_util.ExecuteSQL(sql, null,
      (sucData) => {
        //console.log(sucData.message);
        res.status(200);
        res.json({ "result": "ok", "description": sucData.message });
      },
      (errData) => {
        res.status(200);
        res.json({ "result": "error", "errorCode": "1", "description": errData.message });
        console.log(sql);
      }
    );
  }
})

//FSMS
app.post('/UpdateUnionOrder2', async (req, res) => {
  let body = req.body;
  let sql = "Update machining_union_sheet set ";
  console.log('UpdateUnionOrder2', body);
  try {
    let col = "";
    let val = "";
    let flag = false;
    for (let k = 1; k <= 8; k++) {
      col = 'name' + k.toString();
      val = 'newValue' + k.toString();
      if (body[col] == undefined || body[val] == undefined)
        continue;
      if (k == 1) {
        let m = 1;
        let newValue = "";
        if (body[col] == 'engineer' || body[col] == 'engineer_zuzhuang') {
          newValue = body[val].join(",");
          if (newValue == '') {
            console.log('UpdateUnionOrder2 没有指派工程师');
            res.status(200);
            res.json({ "result": "error", "description": "没有指派工程师" });
            return;
          }
        }
        else if (body[col] == 'stage') {
          let index = parseInt(body[val]);
          if (isNaN(index))
            index = 0;
          let sql2 = "select stage from machining_union_sheet where union_order = '" + body.unionorder + "'";
          let suc = await db_util.query(sql2);
          for (let i = 0; i < index; i++) {
            newValue += suc[0].stage.charAt(i);
          }
          newValue += body.stageValue;
          if (body.newValue12 == undefined) {
            for (let i = index + 1; i < suc[0].stage.length; i++) {
              newValue += suc[0].stage.charAt(i);
            }
          }
          else {
            let index2 = parseInt(body.newValue12);
            for (let i = index + 1; i < index2; i++) {
              newValue += suc[0].stage.charAt(i);
            }
            newValue += body.stageValue2;
            for (let i = index2 + 1; i < suc[0].stage.length; i++) {
              newValue += suc[0].stage.charAt(i);
            }
          }
          if (newValue == suc[0].stage) {
            m = 0;
            console.log(body.unionorder + ' stage不必更新');
          }
        }
        else {
          newValue = body[val];
        }
        if (m == 1) {
          sql += body[col];
          sql += " = '" + newValue + "'";
          flag = true;
        }
      }
      else {
        if (k == 4 && body[col] == "lqsl") // 先改总表再加派件可能会出错，所以就在这里统一处理，2021-09-08
        {
          sql += " where union_order = '" + body.unionorder + "'";

          let sql2 = "select name, delivery_addr from machining_union_sheet where union_order = '" + body.unionorder + "'";
          let ret = await db_util.query(sql2);
          if (ret.length > 0) {
            sql2 = "insert into delivery_sheet values('" + req.body.unionorder + "', '" + ret[0].name + "', '" + body.newValue4 + "', '" + ret[0].delivery_addr + "', '', '', '" + req.body.newValue3 + "')";
            let ret2 = await db_util.query(sql2);
            console.log(sql2 + ', affected rows: ' + ret2.affectedRows);
            let sucData = await db_util.query(sql);
            console.log(sql + ', affected rows: ' + sucData.affectedRows);

            let date = new Date();
            sql2 = "update machining_union_sheet set paijian_time = '" + getMonthDayTime(date, 1, 1) + "'";
            await db_util.query(sql2);

            res.status(200);
            res.json({ "result": "ok", "description": sucData.message });
          }
          else {
            console.log('UpdateUnionOrder2 lqsl', sql2);
            res.status(200);
            res.json({ "result": "error", "description": "not find the unionorder" });
          }
          return;
        }
        if (flag)
          sql += ', ';
        else
          flag = true;
        sql += body[col];
        sql += " = '" + body[val] + "'";
      }
    }
    if (flag == false) {
      console.log('没有需要更新的字段', body);
      res.status(200);
      res.json({ "result": "ok" });
      return;
    }
    sql += " where union_order = '" + body.unionorder + "'";
    console.log(sql);

    let sucData = await db_util.query(sql);
    if (body.name1 == 'engineer' || body.name1 == 'engineer_zuzhuang') {
      sql = "delete from machining_engineer where union_order = '" + body.unionorder + "' and type = '" + body.name1 + "'";
      await db_util.query(sql);
      let suc2 = await db_util.query("select name, job_no from employee");
      let engineers = new Array(body.newValue1.length);
      for (let i = 0; i < body.newValue1.length; i++) {
        let temp = new Array(5);
        temp[0] = body.unionorder;
        temp[1] = "";
        temp[2] = "";
        temp[3] = body.newValue1[i];
        temp[4] = body.name1;
        for (let n = 0; n < suc2.length; n++) {
          if (suc2[n].name == body.newValue1[i]) {
            temp[2] = suc2[n].job_no;
            break;
          }
        }
        engineers[i] = temp;
      }
      sql = "insert into machining_engineer values ?";
      await db_util.query(sql, [engineers]);
    }
    res.status(200);
    res.json({ "result": "ok", "description": sucData.message });
  }
  catch (error) {
    console.log('总表更新失败', sql);
    res.status(200);
    res.json({ "result": "error", "errorCode": "1", "description": error.message });
  }
})

//FSMS
app.post('/UpdateWorkOrder', async (req, res) => {
  let body = req.body;
  console.log('UpdateWorkOrder', body);
  if (body.id == undefined) {
    if (body.unionorder == undefined) {
      res.status(200);
      res.json({ "result": "error", "description": "the unionorder is not set" });
      return;
    }
    else if (body.workorder == undefined) {
      if (body.status == undefined) {
        res.status(200);
        res.json({ "result": "error", "description": "the workorder is not set" });
        return;
      }
    }
  }
  try {
    let flag = false;
    let sql = "select column_name from information_schema.COLUMNS where table_schema = '" + db_util.config.db_name + "' and table_name = 'machining_sheet' ORDER BY ordinal_position ASC";
    let suc3 = await db_util.query(sql);
    sql = "Update machining_sheet set ";
    for (let i = 17; i < suc3.length; i++) // 去掉id、union_order、type、sheet_order... type_flag等等
    {
      if (body[suc3[i].column_name] == undefined)
        continue;
      if (flag)
        sql += ", ";
      sql += suc3[i].column_name;
      sql += " = \'";
      sql += body[suc3[i].column_name];
      sql += '\'';
      flag = true;
    }

    if (flag) {
      sql += " where union_order = '" + body.unionorder + "' and quatity != '0'";
      if (body.workorder != undefined)
        sql += " and sheet_order = '" + body.workorder + "'";
      if (body.type != undefined)
        sql += " and type_flag = '" + body.type + "'";
      if (body.status != undefined && body.status2 != undefined)
        sql += " and status = '" + body.status + "'";
      console.log('更新大表：' + sql);
      let suc4 = await db_util.query(sql);
      if (suc4.affectedRows == 0)
        console.log('更新大表失败');
    }
    else {
      //console.log('大表中没有匹配的栏位可以更新');
    }

    suc3 = null;
    // 更新小表
    sql = "select column_name from information_schema.COLUMNS where table_schema = '" + db_util.config.db_name + "' and table_name = 'dispatch_sheet' ORDER BY ordinal_position ASC";
    suc3 = await db_util.query(sql);
    flag = false;
    sql = "update dispatch_sheet set ";
    for (let i = 31; i < suc3.length; i++) // 去掉id、union_order、type、sheet_order... parentID等等
    {
      if (body[suc3[i].column_name] == undefined)
        continue;
      if (flag)
        sql += ", ";
      sql += suc3[i].column_name;
      sql += " = \'";
      if (suc3[i].column_name == 'engineer_ercijiagong') {
        let temp = "";
        for (let k = 0; k < body.engineer_ercijiagong.length; k++) {
          if (k > 0)
            temp += ",";
          temp += body.engineer_ercijiagong[k];
        }
        sql += temp;
      }
      else {
        sql += body[suc3[i].column_name];
      }
      sql += '\'';
      flag = true;
    }
    if (flag) {
      if (body.workorder == undefined) {
        sql += " where union_order = '" + body.unionorder + "' and rawdata != 0 and gjsl != '0'";
      }
      else {
        let sql2 = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + body.unionorder + "' and ljmc = '" + body.workorder + "' and rawdata = 2";
        let suc2 = await db_util.query(sql2);
        if (suc2.length >= 0) // 2021-12-01，统一用id来操作
        {
          if (body.id == undefined) {
            sql2 = " where union_order = '" + body.unionorder + "' and ljmc = '" + body.workorder + "' and rawdata != 0";
            sql += sql2;
          }
          else {
            sql += " where id = '" + body.id + "'";
          }
        }
        else {
          sql2 = " where union_order = '" + body.unionorder + "' and ljmc = '" + body.workorder + "' and rawdata != 0";
          sql += sql2;
        }
      }
      console.log('更新小表: ' + sql);
      let suc4 = await db_util.query(sql);
      if (suc4.affectedRows == 0) {
        console.log('更新小表失败');
        if (body.timestamp != undefined) {
          let i = parseInt(body.timestamp);
          if (isNaN(i)) {
            console.log('timestamp is invalid');
          }
          else {
            i = parseInt(i / 1000);
            sql = "update machining_union_sheet set priority = " + i + " where union_order = '" + body.unionorder + "'";
            let succ5 = await db_util.query(sql);
            if (succ5.affectedRows == 0) {
              console.log('更新总表失败', sql);
            }
          }
        }
      }
    }

    if (body.status != undefined) {
      let i = 0;
      let index = parseInt(body.status);
      if (index == 4) // 二次加工
        index = 3;
      // status：0/设计；1/编程；2/加工；3/品检；4/二次加工；5/组装；6/总检；7/入库
      sql = "select id, status from dispatch_sheet where gjsl != '0' and union_order = '" + body.unionorder + "'";
      let suc5 = await db_util.query(sql);
      for (let k = 0; k < suc5.length; k++) {
        i = parseInt(suc5[k].status);
        if (i < index) {
          console.log('加工件的状态不一致，设置的状态是', body.status, body.unionorder, suc5[k].id, suc5[k].status);
          sql = "";
          break;
        }
      }
      if (sql.length > 0) // 所有加工件的状态都一致，说明该阶段已经结束了
      {
        let temp = "";
        let date = new Date();
        let endtime = getMonthDayTime(date, 1, 1);
        if (body.status == '2')
          temp = "biancheng_endtime";
        else if (body.status == '3' || body.status == '4') // 非重点尺寸会跳过品检
          temp = "jiagong_endtime";
        else if (body.status == '5')
          temp = "ercijg_endtime";
        else if (body.status == '6')
          temp = "zuzhuang_endtime";
        if (temp.length > 0) {
          let stage = ""; // stage已经由前端通过UpdateUnionOrder2作了更新
          sql = "select stage from machining_union_sheet where union_order = '" + body.unionorder + "'";
          let succ2 = await db_util.query(sql);
          for (i = 0; i < succ2[0].stage.length; i++) {
            if (i < index)
              stage += '0';
            else if (i == index)
              stage += '1';
            else
              stage += succ2[0].stage.charAt(i);
          }
          sql = "update machining_union_sheet set " + temp + " = '" + endtime + "', stage = '" + stage + "' where union_order = '" + body.unionorder + "'";
          await db_util.query(sql);
          console.log(sql);
          sql = "update machining_sheet set status = '" + body.status + "' where union_order = '" + body.unionorder + "' and type_flag = 1";
          await db_util.query(sql);
          console.log(sql);
        }
      }
    }

    if (body.engineer_ercijiagong != undefined) {
      sql = "delete from machining_engineer where union_order = '" + body.unionorder + "' and sheet_order = '" + body.workorder + "' and type = 'engineer_ercijiagong'";
      await db_util.query(sql);
      let suc2 = await db_util.query("select name, job_no from employee");
      let engineers = new Array();
      for (let i = 0; i < body.engineer_ercijiagong.length; i++) {
        let temp = new Array(5);
        temp[0] = body.unionorder;
        temp[1] = body.workorder;
        temp[2] = "";
        temp[3] = body.engineer_ercijiagong[i];
        temp[4] = "engineer_ercijiagong";
        for (let n = 0; n < suc2.length; n++) {
          if (suc2[n].name == body.engineer_ercijiagong[i]) {
            temp[2] = suc2[n].job_no;
            break;
          }
        }
        engineers.push(temp);
      }
      if (engineers.length > 0) {
        sql = "insert into machining_engineer values ?";
        await db_util.query(sql, [engineers]);
      }
    }
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('UpdateWorkOrder error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": errData.message });
  }
})

//NOUSE
app.post('/ResetUnionOrder', async (req, res) => {
  let body = req.body;
  if (body.unionorder == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "the unionorder is not set" });
    return;
  }
  console.log('ResetUnionOrder: ' + body.unionorder);
  try {
    let sql = "delete from machining_sheet where union_order = '" + body.unionorder + "'";
    await db_util.query(sql);
    sql = "delete from dispatch_sheet where union_order = '" + body.unionorder + "'";
    await db_util.query(sql);

    let flag = false;
    sql = "select column_name from information_schema.COLUMNS where table_schema = '" + db_util.config.db_name + "' and table_name = 'machining_union_sheet' ORDER BY ordinal_position ASC";
    let suc3 = await db_util.query(sql);
    sql = "Update machining_union_sheet set ";
    for (let i = 13; i < suc3.length; i++) {
      if (suc3[i].column_name == 'code19' || suc3[i].column_name == 'price')
        continue;
      if (flag)
        sql += ", ";
      sql += suc3[i].column_name;
      sql += " = \'";
      if (suc3[i].column_name == 'stage') {
        sql += '1000000000';
      }
      sql += '\'';
      flag = true;
    }
    sql += " where union_order = '" + body.unionorder + "'";
    await db_util.query(sql);

    sql = "select * from machining_files where union_order = '" + body.unionorder + "'";
    let suc1 = await db_util.query(sql);
    for (let i = 0; i < suc1.length; i++) {
      fs.unlink(suc1[i].file_path, function (err) { });
    }
    sql = "delete from machining_files where union_order = '" + body.unionorder + "'";
    await db_util.query(sql);

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('ResetUnionOrder error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": errData.message });
  }
})


var g_cncInfo = null;
function loadCNC() {
  if (g_cncInfo == null)
    g_cncInfo = new Array;
  db_util.ExecuteSQL("select * from cnc", null,
    (sucData) => {
      if (sucData.length > 0) {
        if (g_cncInfo.length > 0)
          g_cncInfo.splice(0, g_cncInfo.length);
        sucData.forEach(element => {
          if (element.isRemoved == 0)
            g_cncInfo.push(element);
        });
        for (let i = 0; i < g_cncInfo.length; i++) {
          //g_cncInfo[i].reserved2 = 8;
          g_cncInfo[i]["lastmode"] = "";
          g_cncInfo[i]["lastmode_starttime"] = "";
          g_cncInfo[i]["lastmode_lasttime"] = "";
        }
        console.log("succeed to load cnc data, total " + g_cncInfo.length);
      }
      else {
        console.log("the table cnc is empty");
      }
    },
    (errData) => {
      console.log("failed to query table cnc: " + errData.message);
    }
  );
}

function getcnc(stuff, length, width, quatity) {
  let json = {};
  json["name"] = "";
  json["id"] = "";
  if (g_cncInfo == undefined)
    return json;
  if (g_cncInfo.length < 1)
    return json;
  if (stuff == '' || length == '')
    return json;
  if (length[0] == 'D' || length[0] == 'd') {
    let len = length.substr(1);
    for (let i = 0; i < g_cncInfo.length; i++) {
      if (g_cncInfo[i].diameter_max < 1)
        continue;
      if (len <= g_cncInfo[i].diameter_max && width <= g_cncInfo[i].length_max) {
        json["name"] = g_cncInfo[i].name;
        json["id"] = g_cncInfo[i].id;
      }
      break;
    }
  }
  else {
    let len_min = 3000;
    let index = 100;
    for (let i = 0; i < g_cncInfo.length; i++) {
      if (g_cncInfo[i].diameter_max > 0)
        continue;
      let temp = g_cncInfo[i].stuff_range;
      if (temp.length < 1) {
        for (let k = 0; k < g_cncInfo.length; k++) {
          if (g_cncInfo[k].id == g_cncInfo[i].reserved1) {
            temp = g_cncInfo[k].stuff_range;
            break;
          }
        }
      }
      if (temp.indexOf(stuff) < 0)
        continue;
      if (length > g_cncInfo[i].length_max)
        continue;
      if (width > g_cncInfo[i].width_max)
        continue;
      if ((g_cncInfo[i].length_max - length) < len_min) {
        len_min = g_cncInfo[i].length_max - length;
        index = i;
      }
    }
    if (index < g_cncInfo.length) {
      let arr = new Array;
      for (let k = 0; k < g_cncInfo.length; k++) {
        if (g_cncInfo[k].length_max == g_cncInfo[index].length_max)
          arr.push(k);
      }
      if (arr.length > 1) {
        /*var k = Math.round(Math.random() * arr.length);
        if(k>=arr.length)
          k = arr.length - 1;
        index = arr[k];
        console.log("random: " + k);*/
        len_min = 3000;
        let newIndex = index;
        for (let k = 0; k < arr.length; k++) {
          index = arr[k];
          if (g_cncInfo[index].loading < len_min) {
            len_min = g_cncInfo[index].loading;
            newIndex = index;
          }
        }
        index = newIndex;
      }
      g_cncInfo[index].loading = (parseInt(g_cncInfo[index].loading) + parseInt(quatity));
      json["name"] = g_cncInfo[index].name;
      json["id"] = g_cncInfo[index].id;
      json["loading"] = g_cncInfo[index].loading;
    }
  }
  return json;
}

function getCNCOperatingMode(Model, mode) {
  let ret = mode;
  if (Model == "FV102A") // Fanuc-a-4ax
  {
    if (mode == 3)
      ret = "编辑模式";
    else if (mode == 2)
      ret = "记忆模式";
    else if (mode == 0)
      ret = "纸带模式";
  }
  else if (Model == "TMT-50") // Mitsubishi
  {
    if (mode == 99)
      ret = "手轮";
    else if (mode == 1)
      ret = "编辑";
    else if (mode == 2)
      ret = "自动";
    else if (mode == 0)
      ret = "寸动";
  }
  else if (Model == "Fanuc-0i MF") // Fanuc-Z
  {
    if (mode == 1)
      ret = "编辑模式";
    else if (mode == 2)
      ret = "记忆模式";
    else if (mode == 0)
      ret = "纸带模式";
  }
  else {
    if (mode == 2)
      ret = "自动";
    else if (mode == 0)
      ret = "手动";
  }
  return ret;
}

function getCNCOperatingStatus(Model, status) {
  let ret = status;
  if (Model == "FV102A") // Fanuc-a-4ax
  {
    if (status == 0)
      ret = "待机";
    else if (status == 2)
      ret = "运行";
  }
  else if (Model == "TMT-50") // Mitsubishi
  {
    if (status == 1)
      ret = "待机";
    else if (status == 2)
      ret = "运行";
    else if (status == 4)
      ret = "报警";
  }
  else if (Model == "Fanuc-0i MF") // Fanuc-Z
  {
    if (status == 0)
      ret = "待机";
    else if (status == 2)
      ret = "运行";
  }
  else {
    if (status == 0)
      ret = "手动";
    else if (status == 2)
      ret = "自动";
    else if (status == 3)
      ret = "报警";
  }
  return ret;
}

async function StatisticDetail(body_MachineName, body_starttime, body_endtime) {
  var array = new Array();
  var arrIndex = {};
  var arrInfo = new Array();
  var MachineName = "";
  if (body_MachineName != undefined)
    MachineName = body_MachineName;
  for (var i = 0; i < g_cncInfo.length; i++) {
    var json = {};
    json["lastProgram"] = "";
    json["lastToolID"] = "";
    arrInfo.push(json);
    arrIndex[g_cncInfo[i].MachineName] = i;
  }
  var flag = false;
  var sql = "select * from cncdata";
  if (MachineName.length > 0) {
    if (flag) {
      sql += " and MachineName = '" + MachineName + "'";
    }
    else {
      flag = true;
      sql += " where MachineName = '" + MachineName + "'";
    }
  }
  if (body_starttime != undefined) {
    if (flag) {
      sql += " and fmtTime >= '" + body_starttime + "'";
    }
    else {
      flag = true;
      sql += " where fmtTime >= '" + body_starttime + "'";
    }
  }
  if (body_endtime != undefined) {
    if (flag) {
      sql += " and fmtTime < '" + body_endtime + "'";
    }
    else {
      flag = true;
      sql += " where fmtTime < '" + body_endtime + "'";
    }
  }
  if (flag) {
    sql += " and length(program) > 0 and length(activetoolid) > 0";
  }
  else {
    flag = true;
    sql += " where length(program) > 0 and length(activetoolid) > 0";
  }
  sql += " ORDER BY Time ASC";
  console.log(sql);
  try {
    let suc = await db_util.query(sql);
    var index = -1;
    for (var k = 0; k < suc.length; k++) {
      index = arrIndex[suc[k].MachineName];
      if (isNaN(index))
        continue;
      if (suc[k].activetoolid == "0")
        continue;
      if (arrInfo[index]["lastProgram"] == suc[k].program && arrInfo[index]["lastToolID"] == suc[k].activetoolid)
        continue;
      arrInfo[index]["lastProgram"] = suc[k].program;
      arrInfo[index]["lastToolID"] = suc[k].activetoolid;

      var json = {};
      json["MachineModel"] = g_cncInfo[index].MachineModel;
      json["MachineName"] = g_cncInfo[index].MachineName;
      json["status"] = suc[k].Operation_Mode;
      json["operatingmode"] = getCNCOperatingMode(json["MachineModel"], suc[k].operatingmode);
      json["operatingstatus"] = getCNCOperatingStatus(json["MachineModel"], suc[k].operatingstatus);
      json["feedrate"] = suc[k].feedrate;
      json["feedrateoverride"] = suc[k].feedrateoverride;
      json["actualspeed"] = suc[k].actualspeed;
      json["speedoverride"] = suc[k].speedoverride;
      json["program"] = suc[k].program;
      json["activetoolid"] = suc[k].activetoolid;
      json["cycletime"] = suc[k].cycletime;
      json["operatingtime"] = suc[k].operatingtime;
      var escapedTime = 0;
      var onTime = 0;
      if (suc.length > 1) {
        var runTime = 0;
        var pcsTime = 0;
        var last_time = 0;
        for (var i = 0; i < suc.length; i++) {
          if (suc[i].MachineName != json["MachineName"])
            continue;
          if (suc[i].program != json["program"])
            continue;
          if (suc[i].activetoolid != json["activetoolid"])
            continue;

          if (suc[i].evt_type == "Run")
            runTime = parseInt(suc[i].Time);
          else if (suc[i].evt_type == "Pcs")
            pcsTime = parseInt(suc[i].Time);
          if (last_time > 0 && (suc[i].Time - last_time) < g_nOffTime) {
            onTime += (parseInt(suc[i].Time) - last_time);
          }
          last_time = parseInt(suc[i].Time);
        }
        if (runTime > 0 && pcsTime > 0) {
          if (pcsTime > runTime)
            escapedTime = pcsTime - runTime;
          else
            escapedTime = runTime - pcsTime;
        }
        else {
          if (pcsTime > 0) // 只有结束时间，没有开始时间
            escapedTime = 1;
          else if (runTime > 0)
            onTime = last_time - runTime;
        }
      }
      if (escapedTime >= 120 * 1000 || (escapedTime == 0 && onTime > 0)) {
        if (escapedTime >= 120 * 1000)
          onTime = escapedTime;
        onTime = parseInt(onTime / 1000);
        var h = parseInt(onTime / 3600);
        var m = parseInt((onTime - h * 3600) / 60);
        var s = onTime - h * 3600 - m * 60;
        if (h < 10)
          suc[k].cycletime = "0";
        suc[k].cycletime += h;
        suc[k].cycletime += ":";
        if (m < 10)
          suc[k].cycletime += "0";
        suc[k].cycletime += m;
        suc[k].cycletime += ":";
        if (s < 10)
          suc[k].cycletime += "0";
        suc[k].cycletime += s;
        json["cycletime"] = suc[k].cycletime;
        array.push(json);
      }
    }
  }
  catch (err) {
    console.log('StatisticDetail error: ' + err.message);
  }
  return array;
}

//NOUSE
app.post('/QueryCncDetail', async (req, res) => {
  let date = new Date();
  console.log('QueryCncDetail from ' + req.ip + ' on ' + getMonthDayTime(date, 1, 1));
  if (req.body.starttime == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set a parameter of starttime" });
    return;
  }
  let array = await StatisticDetail(req.body.MachineName, req.body.starttime, req.body.endtime);
  res.status(200);
  res.json({ "result": "ok", "order": array });
})

//FSMS
app.post('/QueryCncInfo', async (req, res) => {
  let date = new Date();
  //console.log('QueryCncInfo from ' + req.ip + ' on ' + date.toLocaleString()); 
  let array = new Array();
  if (g_cncInfo == undefined) {
    res.status(200);
    res.json({ "result": "ok", "order": array });
    return;
  }
  let MachineName = "";
  if (req.body.MachineName != undefined)
    MachineName = req.body.MachineName;
  for (let i = 0; i < g_cncInfo.length; i++) {
    if (MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName)
      continue;
    let json = {};
    json["id"] = g_cncInfo[i].id;
    json["name"] = g_cncInfo[i].name;
    json["MachineName"] = g_cncInfo[i].MachineName;
    json["MachineModel"] = g_cncInfo[i].MachineModel;
    json["MachineSN"] = g_cncInfo[i].MachineSN;
    if (req.body.status == undefined) {
      json["diameter_max"] = g_cncInfo[i].diameter_max;
      json["length_max"] = g_cncInfo[i].length_max;
      json["width_max"] = g_cncInfo[i].width_max;
      json["stuff_type"] = g_cncInfo[i].stuff_type;
      if (g_cncInfo[i].stuff_range.length > 0) {
        json["stuff_range"] = g_cncInfo[i].stuff_range;
      }
      else {
        let k = i - 1;
        while (k >= 0) {
          if (g_cncInfo[k].stuff_range.length > 0) {
            json["stuff_range"] = g_cncInfo[k].stuff_range;
            break;
          }
          else
            k -= 1;
        }
      }
    }
    else if (req.body.status != "Alarm") {
      json["status"] = "OFF";
    }
    array.push(json);
  }
  if (req.body.status == undefined) {
    let sql = "select * from cnc where isRemoved != 0";
    let suc = await db_util.query(sql);
    for (let i = 0; i < suc.length; i++) {
      let json = {};
      json["id"] = suc[i].id;
      json["name"] = suc[i].name;
      json["MachineName"] = suc[i].MachineName;
      json["MachineModel"] = suc[i].MachineModel;
      json["MachineSN"] = suc[i].MachineSN;
      json["diameter_max"] = suc[i].diameter_max;
      json["length_max"] = suc[i].length_max;
      json["width_max"] = suc[i].width_max;
      json["stuff_type"] = suc[i].stuff_type;
      json["stuff_range"] = suc[i].stuff_range;
      json["status"] = "OFF";
      array.push(json);
    }
    res.status(200);
    res.json({ "result": "ok", "order": array });
    return;
  }
  //if( req.body.status.length > 0 )
  //  console.log('QueryCncInfo ' + req.body.status);
  if (req.body.status == "Alarm") {
    let sql = "select MachineName, Time, fmtTime, alarmstatus from cncdata where alarmstatus != 'False' and alarmstatus != 'True'";
    if (MachineName.length > 0)
      sql += " and MachineName = '" + MachineName + "'";
    if (req.body.starttime != undefined)
      sql += " and fmtTime >= '" + req.body.starttime + "'";
    if (req.body.endtime != undefined)
      sql += " and fmtTime < '" + req.body.endtime + "'";
    sql += " ORDER BY Time ASC";
    console.log(sql);
    try {
      let suc = await db_util.query(sql);
      for (let i = 0; i < array.length; i++) {
        let alarms = new Array();
        let last_time = "";
        let last_alarm = "";
        let flag = false;
        for (let k = 0; k < suc.length; k++) {
          if (array[i].MachineName == suc[k].MachineName) {
            if (suc[k].alarmstatus.length > 0) {
              flag = false;
              if (last_alarm != suc[k].alarmstatus) {
                flag = true;
              }
              else if ((suc[k].Time - last_time) > 60000) {
                flag = true;
              }
              if (flag == true) {
                let json = {};
                json["time"] = suc[k].fmtTime;
                json["alarm"] = suc[k].alarmstatus;
                alarms.push(json);
              }
              last_time = suc[k].Time;
              last_alarm = suc[k].alarmstatus;
            }
          }
        }
        array[i]["alarms"] = alarms;
      }
      res.status(200);
      res.json({ "result": "ok", "order": array });
      return;
    }
    catch (error) {
      console.log('QueryCncInfo - Alarm error: ' + error.message);
      let alarms = new Array();
      res.status(200);
      res.json({ "result": "error", "order": array, "description": err.message });
      return;
    }
  }
  else if (req.body.status == "WorkTime") {
    let array = new Array();
    let MachineName = "";
    if (req.body.MachineName != undefined)
      MachineName = req.body.MachineName;
    let flag = false;
    let condition = "";
    if (req.body.starttime != undefined) {
      if (flag) {
        condition += " and fmtTime >= '" + req.body.starttime + "'";
      }
      else {
        flag = true;
        condition += " where fmtTime >= '" + req.body.starttime + "'";
      }
    }
    if (req.body.endtime != undefined) {
      if (flag) {
        condition += " and fmtTime < '" + req.body.endtime + "'";
      }
      else {
        flag = true;
        condition += " where fmtTime < '" + req.body.endtime + "'";
      }
    }
    if (flag) {
      condition += " and length(program) > 0 and length(activetoolid) > 0";
    }
    else {
      flag = true;
      condition += " where length(program) > 0 and length(activetoolid) > 0";
    }
    sql += " ORDER BY Time ASC";
    try {
      let sql = "select MachineName, program, activetoolid from cncdata" + condition;
      if (MachineName.length > 0)
        sql += " and MachineName = '" + MachineName + "'";
      sql += " GROUP BY program ORDER BY Time ASC";
      let suc = await db_util.query(sql);
      let starttime = 0;
      let endtime = 0;
      let date = new Date();
      for (let i = 0; i < suc.length; i++) {
        if (suc[i].activetoolid == "0")
          continue;
        sql = "select evt_type, Time, program, activetoolid from cncdata";
        sql += condition;
        sql += " and MachineName = '" + suc[i].MachineName + "'";
        sql += " and program = '" + suc[i].program + "'";
        sql += " ORDER BY id ASC";
        let suc2 = await db_util.query(sql);
        starttime = 0;
        endtime = 0;
        for (let k = 0; k < suc2.length; k++) {
          if (suc2[k].activetoolid == "0")
            continue;
          if (suc2[k].evt_type == "Run") // 开始
            starttime = parseInt(suc2[k].Time);
          else if (suc2[k].evt_type == "Pcs")
            endtime = parseInt(suc2[k].Time);
          if (starttime > 0 && endtime > 0)
            break;
        }
        if (starttime == 0 || endtime == 0 || starttime >= endtime) {
          starttime = 0;
          endtime = 0;
        }
        if (starttime == 0)
          starttime = parseInt(suc2[0].Time);
        if (endtime == 0)
          endtime = parseInt(suc2[suc2.length - 1].Time);
        let json = {};
        date.setTime(starttime);
        json["MachineName"] = suc[i].MachineName;
        json["starttime"] = getMonthDayTime(date, 1, 1);
        json["program"] = suc[i].program;
        endtime = parseInt((endtime - starttime) / 1000);
        starttime = parseInt(endtime / 3600);
        if (starttime < 9)
          sql = '0' + starttime + ':';
        else
          sql = starttime + ':';
        endtime -= (starttime * 3600);
        starttime = parseInt(endtime / 60);
        if (starttime < 9)
          sql += ('0' + starttime + ':');
        else
          sql += (starttime + ':');
        endtime -= (starttime * 60);
        if (endtime < 9)
          sql += ('0' + endtime);
        else
          sql += endtime;
        json["operatingtime"] = sql;
        array.push(json);
      }
      res.status(200);
      res.json({ "result": "ok", "order": array });
      return;
    }
    catch (error) {
      console.log('查询加工总时间 error: ' + error.message);
      let alarms = new Array();
      res.status(200);
      res.json({ "result": "error", "order": array, "description": error.message });
      return;
    }
  }
  else if (req.body.status == "cncTime") {
    if (req.body.starttime == undefined) {
      console.log('查询cnc加工总时间，但没有指定加工日期');
      res.status(200);
      res.json({ "result": "ok", "order": array });
      return;
    }
    let sql = "select union_order, quatity from machining_union_sheet where status = 0";
    try {
      let suc = await db_util.query(sql);
      for (let i = 0; i < array.length; i++) {
        array[i]["cncTime"] = 0.0;
        for (let j = 0; j < suc.length; j++) {
          sql = "select estimate_time from dispatch_sheet where gjsl != '0' and union_order = '" + suc[j].union_order + "' and cnc = '" + array[i].name + "' and jiagongriqi like '" + req.body.starttime + "%'";
          let suc2 = await db_util.query(sql);
          for (let k = 0; k < suc2.length; k++) {
            let t = parseFloat(suc2[k].estimate_time);
            if (isNaN(t))
              t = 0.0;
            array[i]["cncTime"] += t;
          }
        }
        array[i]["cncTime"] = dotFixed(array[i]["cncTime"]);
      }
      res.status(200);
      res.json({ "result": "ok", "order": array });
      return;
    }
    catch (error) {
      console.log('查询cnc加工总时间 error: ' + error.message);
      let alarms = new Array();
      res.status(200);
      res.json({ "result": "error", "order": array, "description": error.message });
      return;
    }
  }
  else {
    let sql = "select * from cncdata";
    if (MachineName.length > 0)
      sql += " where MachineName = '" + MachineName + "' order by id desc limit 2";
    else
      sql += " order by id desc limit " + 3 * g_cncInfo.length;
    //console.log(sql);
    try {
      let suc = await db_util.query(sql);
      let suc4 = await db_util.query("select sheet_order, file_path from machining_files where union_order = 'kanban' ORDER BY id DESC");
      for (let i = 0; i < array.length; i++) {
        array[i]["url"] = "";
        for (let k = 0; k < suc4.length; k++) {
          if (suc4[k].sheet_order == array[i].MachineName) {
            array[i]["url"] = suc4[k].file_path;
            break;
          }
        }
      }
      // 查询设备当前状态
      let currTime = Date.now() - g_nWaitTime;
      {
        //var ct = new Date(currTime);
        //var st = new Date(parseInt(suc[0].Time));
        //console.log('前3分钟时间：' + ct.toLocaleString() + '，数据最新时间：' + st.toLocaleString());
      }
      if (g_lastUpdateTime > currTime) {
        for (let i = 0; i < array.length; i++) {
          for (let k = 0; k < suc.length; k++) {
            if (array[i].MachineName == suc[k].MachineName) {
              array[i].status = suc[k].Operation_Mode;
              array[i]["operatingmode"] = getCNCOperatingMode(array[i].MachineModel, suc[k].operatingmode);
              array[i]["operatingstatus"] = getCNCOperatingStatus(array[i].MachineModel, suc[k].operatingstatus);
              array[i]["cycletime"] = suc[k].cycletime;
              array[i]["operatingtime"] = suc[k].operatingtime;
              array[i]["partcount"] = suc[k].partcount;
              array[i]["feedrate"] = suc[k].feedrate;
              array[i]["feedrateoverride"] = suc[k].feedrateoverride;
              array[i]["program"] = suc[k].program;
              array[i]["actualspeed"] = suc[k].actualspeed;
              array[i]["speedoverride"] = suc[k].speedoverride;
              array[i]["activetoolid"] = suc[k].activetoolid;
              array[i]["union_order"] = "";
              if (g_cncInfo[i]["lastmode_starttime"] == "") {
                array[i]["status_starttime"] = "";
              }
              else {
                let date = new Date(parseInt(g_cncInfo[i]["lastmode_starttime"]));
                array[i]["status_starttime"] = getMonthDayTime(date, 1, 1);
              }
              break;
            }
          }
        }
        if (array.length == 1 && array[0]["program"].length > 0) {
          sql = "select union_order from dispatch_sheet where gjsl != '0' and cxmc = '" + array[0]["program"] + "'";
          console.log(sql);
          let suc2 = await db_util.query(sql);
          if (suc2.length > 0)
            array[0]["union_order"] = suc2[0].union_order;
          res.status(200);
          res.json({ "result": "ok", "order": array });
          return;
        }
        else {
          res.status(200);
          res.json({ "result": "ok", "order": array });
          return;
        }
      }
      else {
        for (let i = 0; i < array.length; i++) {
          for (let k = 0; k < suc.length; k++) {
            if (array[i].MachineName == suc[k].MachineName) {
              array[i]["status"] = "OFF";
              array[i]["status_starttime"] = suc[k].fmtTime;
              break;
            }
          }
        }
        res.status(200);
        res.json({ "result": "ok", "order": array });
        return;
      }
    }
    catch (error) {
      res.status(200);
      let alarms = new Array();
      res.json({ "result": "ok", "order": array, "description": error.message });
      return;
    }
  }
})

async function StatisticUtilization(body_MachineName, body_starttime, body_endtime, body_mode) // 稼动率统计
{
  let flag = false;
  let MachineName = "";
  if (body_MachineName != undefined)
    MachineName = body_MachineName;
  //let date = new Date();
  let temp = new Array(); // 返回值
  let array = new Array();
  let arrIndex = {};
  for (let i = 0; i < g_cncInfo.length; i++) {
    if (MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName)
      continue;
    let json = {};
    json["name"] = g_cncInfo[i].name;
    json["MachineName"] = g_cncInfo[i].MachineName;
    json["start_time"] = 0; // 第一次记录的时间
    json["last_time"] = 0; // 上一次记录的时间，用于判断是否关机
    json["last_mode"] = "";
    json["run_time"] = 0;
    json["run_start"] = 0;
    json["run_end"] = 0;
    json["idle_time"] = 0;
    json["idle_start"] = 0;
    json["idle_end"] = 0;
    json["idle_count"] = 0;
    json["shutdown_time"] = 0;
    json["shutdown_start"] = 0;
    json["shutdown_end"] = 0;
    json["shutdown_count"] = 0;
    json["off_time"] = 0;
    json["off_start"] = 0;
    json["off_end"] = 0;
    json["off_count"] = 0;
    json["lastID"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }
  let sql = "select id, MachineName, Time, Operation_Mode from cncdata";
  if (body_starttime != undefined) {
    if (body_starttime < '2020-06-01 08:00:00') {
      console.log('StatisticUtilization starttime error: ' + body_starttime);
      array = null;
      return temp;
    }
    if (flag) {
      sql += " and fmtTime >= '" + body_starttime + "'";
    }
    else {
      flag = true;
      sql += " where fmtTime >= '" + body_starttime + "'";
    }
  }
  else // 如果没有设置开始时间，那就统计所有数据
  {
    try {
      let suc2 = await db_util.query("select * from cncstat");
      for (let k = 0; k < suc2.length; k++) // 添加新的统计数据
      {
        if (k == 0) {
          if (flag) {
            sql += " and id > '" + suc2[0].lastID + "'";
          }
          else {
            flag = true;
            sql += " where id > '" + suc2[0].lastID + "'";
          }
        }
        for (let i = 0; i < array.length; i++) {
          if (array[i].MachineName == suc2[k].MachineName) {
            array[k]["last_mode"] = suc2[i].lastMode;
            array[k]["last_time"] = suc2[i].lastMode_starttime;
            array[i]["run_time"] += suc2[k].run_time * 1000;
            array[i]["idle_time"] += suc2[k].idle_time * 1000;
            array[i]["idle_count"] += suc2[k].idle_count;
            array[i]["shutdown_time"] += suc2[k].shutdown_time * 1000;
            array[i]["shutdown_count"] += suc2[k].shutdown_count;
            array[i]["off_time"] += suc2[k].off_time * 1000;
            array[i]["off_count"] += suc2[k].off_count;
            array[i]["lastID"] = suc2[k].lastID;
            if (array[k]["last_mode"] == "Run")
              array[i]["run_start"] = array[k]["last_time"];
            else if (array[k]["last_mode"] == "Idle")
              array[i]["idle_start"] = array[k]["last_time"];
            else if (array[k]["last_mode"] == "Shutdown")
              array[i]["shutdown_start"] = array[k]["last_time"];
            else if (array[k]["last_mode"] == "OFF")
              array[i]["off_start"] = array[k]["last_time"];
            break;
          }
        }
      }
    }
    catch (error) {
      console.log('StatisticUlitization: cncstat, ' + error.message);
    }
  }
  if (body_endtime != undefined) {
    if (flag) {
      sql += " and fmtTime < '" + body_endtime + "'";
    }
    else {
      flag = true;
      sql += " where fmtTime < '" + body_endtime + "'";
    }
  }
  if (MachineName.length > 0) {
    if (flag) {
      sql += " and MachineName = '" + MachineName + "'";
    }
    else {
      flag = true;
      sql += " where MachineName = '" + MachineName + "'";
    }
  }
  sql += " ORDER BY Time ASC";
  //console.log('统计稼动率：' + sql);
  try {
    let suc = await db_util.query(sql);
    let index = -1;
    let currentTime = 0;
    for (let k = 0; k < suc.length; k++) {
      index = arrIndex[suc[k].MachineName];
      if (isNaN(index))
        continue;
      currentTime = parseInt(suc[k].Time);
      if (array[index]["start_time"] == 0)
        array[index]["start_time"] = currentTime;
      // 判断是否有关机过程
      if (array[index]["last_time"] > 0 && (currentTime - array[index]["last_time"]) > g_nOffTime) // 间隔时间大于10分钟
      {
        //console.log(suc[k].MachineName + '关机，从' + array[index]["last_time"] + '到' + currentTime + ', 时长：' + parseInt((currentTime - array[index]["last_time"])));
        array[index]["off_time"] += (currentTime - array[index]["last_time"]);
        array[index]["off_count"]++;

        if (array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0) {
          array[index]["run_time"] += (array[index]["last_time"] - array[index]["run_start"]);
        }
        if (array[index]["last_mode"] == "Idle" && array[index]["idle_start"] > 0) {
          array[index]["idle_time"] += (array[index]["last_time"] - array[index]["idle_start"]);
        }
        if (array[index]["last_mode"] == "Shutdown" && array[index]["shutdown_start"] > 0) {
          array[index]["shutdown_time"] += (array[index]["last_time"] - array[index]["shutdown_start"]);
        }
        if (array[index]["last_mode"] == "OFF" && array[index]["off_start"] > 0) {
          array[index]["off_time"] += (array[index]["last_time"] - array[index]["off_start"]);
        }
        array[index]["run_start"] = 0;
        array[index]["idle_start"] = 0;
        array[index]["shutdown_start"] = 0;
        array[index]["off_start"] = 0;
        array[index]["last_time"] = 0;
      }
      if (k == 0 && array[index]["last_time"] > 0) {
        let tempTime = currentTime;
        currentTime = array[index]["last_time"]; // 计算的时候避免这两个值之间的差漏算了
        array[index]["last_time"] = tempTime;
      }
      else {
        array[index]["last_time"] = currentTime;
      }
      array[index]["last_mode"] = suc[k].Operation_Mode;
      array[index]["lastID"] = parseInt(suc[k].id);

      // 计算运行时间
      array[index]["run_end"] = currentTime;
      if (suc[k].Operation_Mode == "Run") {
        if (array[index]["run_start"] == 0)
          array[index]["run_start"] = currentTime;
      }
      else if (array[index]["run_start"] > 0) {
        array[index]["run_time"] += (array[index]["run_end"] - array[index]["run_start"]);
        array[index]["run_start"] = 0;
        array[index]["run_end"] = 0;
      }
      // 计算等待时间
      array[index]["idle_end"] = currentTime;
      if (suc[k].Operation_Mode == "Idle") {
        if (array[index]["idle_start"] == 0) {
          array[index]["idle_start"] = currentTime;
          array[index]["idle_count"]++;
        }
      }
      else if (array[index]["idle_start"] > 0) {
        array[index]["idle_time"] += (array[index]["idle_end"] - array[index]["idle_start"]);
        array[index]["idle_start"] = 0;
        array[index]["idle_end"] = 0;
      }
      // 计算停机时间
      array[index]["shutdown_end"] = currentTime;
      if (suc[k].Operation_Mode == "Shutdown") {
        if (array[index]["shutdown_start"] == 0) {
          array[index]["shutdown_start"] = currentTime;
          array[index]["shutdown_count"]++;
        }
      }
      else if (array[index]["shutdown_start"] > 0) {
        array[index]["shutdown_time"] += (array[index]["shutdown_end"] - array[index]["shutdown_start"]);
        array[index]["shutdown_start"] = 0;
        array[index]["shutdown_end"] = 0;
      }
      // 计算关机时间
      array[index]["off_end"] = currentTime;
      if (suc[k].Operation_Mode == "OFF") {
        if (array[index]["off_start"] == 0) {
          array[index]["off_start"] = currentTime;
          array[index]["off_count"]++;
        }
      }
      else if (array[index]["off_start"] > 0) {
        array[index]["off_time"] += (array[index]["off_end"] - array[index]["off_start"]);
        array[index]["off_start"] = 0;
        array[index]["off_end"] = 0;
      }
    }
    for (index = 0; index < array.length; index++) {
      if (array[index]["run_start"] > 0 && array[index]["run_end"] > array[index]["run_start"])
        array[index]["run_time"] += (array[index]["run_end"] - array[index]["run_start"]);
      if (array[index]["idle_start"] > 0 && array[index]["idle_end"] > array[index]["idle_start"])
        array[index]["idle_time"] += (array[index]["idle_end"] - array[index]["idle_start"]);
      if (array[index]["shutdown_start"] > 0 && array[index]["shutdown_end"] > array[index]["shutdown_start"])
        array[index]["shutdown_time"] += (array[index]["shutdown_end"] - array[index]["shutdown_start"]);
      if (array[index]["off_start"] > 0 && array[index]["off_end"] > array[index]["off_start"])
        array[index]["off_time"] += (array[index]["off_end"] - array[index]["off_start"]);
    }
    /* 不必重新计算 2020/08/10
    // 重新计算关机时间：总时间 - 运行时间 - 等待时间 - 故障时间
    var starttime = 0;
    var endtime = 0;
    if( body_starttime != undefined )
      starttime = Date.parse(body_starttime);
    if( suc.length > 0 )
      starttime = parseInt(suc[0].Time);
    if( body_endtime != undefined )
      endtime = Date.parse(body_endtime);
    if( suc.length > 1 )
      endtime = parseInt(suc[suc.length-1].Time);
    for(var i=0; i<array.length; i++)
    {
      currentTime = (endtime - starttime) - array[i]["run_time"] - array[i]["idle_time"] - array[i]["shutdown_time"];
      if( currentTime > array[i]["off_time"] )
        array[i]["off_time"] = currentTime;
    }*/
    for (let i = 0; i < array.length; i++) {
      let json = {};
      json["name"] = array[i]["name"];
      json["MachineName"] = array[i]["MachineName"];
      json["run_time"] = array[i]["run_time"];
      json["total_time"] = array[i]["last_time"] - array[i]["start_time"]; //endtime - starttime;
      json["idle_time"] = array[i]["idle_time"];
      json["idle_count"] = array[i]["idle_count"];
      json["shutdown_time"] = array[i]["shutdown_time"];
      json["shutdown_count"] = array[i]["shutdown_count"];
      json["off_time"] = array[i]["off_time"];
      json["off_count"] = array[i]["off_count"];
      json["last_mode"] = array[i]["last_mode"];
      json["last_time"] = array[i]["last_time"];
      json["start_time"] = array[i]["start_time"];
      if (suc.length > 0)
        json["lastID"] = suc[suc.length - 1].id;
      else
        json["lastID"] = array[i]["lastID"];
      json["last_id"] = array[i]["lastID"];
      temp.push(json);
      //console.log(json["MachineName"] + '运行时间' + json["run_time"] + '，关机时间' + json["off_time"] + '，总时长' + json["total_time"]);
    }

    if (body_starttime == undefined && suc.length > 0) // 查询某个时间段就不用去更新表cncstat了
    {
      for (let i = 0; i < array.length; i++) {
        array[i]["lastID"] = suc[suc.length - 1].id;
        array[i]["run_time"] = parseInt(array[i]["run_time"] / 1000 + 0.5);
        array[i]["idle_time"] = parseInt(array[i]["idle_time"] / 1000 + 0.5);
        array[i]["shutdown_time"] = parseInt(array[i]["shutdown_time"] / 1000 + 0.5);
        array[i]["off_time"] = parseInt(array[i]["off_time"] / 1000 + 0.5);

        let sql = "select * from cncstat where MachineName = '" + array[i]["MachineName"] + "'";
        let row = await db_util.query(sql);
        if (row.length == 0) {
          sql = "insert into cncstat values('" + array[i]["MachineName"] + "', '" + array[i]["last_mode"] + "', ";
          sql += "'" + array[i]["last_time"] + "', '" + array[i]["lastID"] + "', '" + array[i]["run_time"] + "', ";
          sql += "'" + array[i]["idle_time"] + "', '" + array[i]["idle_count"] + "', ";
          sql += "'" + array[i]["shutdown_time"] + "', '" + array[i]["shutdown_count"] + "', ";
          sql += "'" + array[i]["off_time"] + "', '" + array[i]["off_count"] + "')";
          await db_util.query(sql);
        }
        else {
          sql = "update cncstat set lastMode = '" + array[i]["last_mode"] + "', lastMode_starttime = '" + array[i]["last_time"] + "', ";
          sql += "lastID = '" + array[i]["lastID"] + "', run_time = '" + array[i]["run_time"] + "', "
          sql += "idle_time = '" + array[i]["idle_time"] + "', idle_count = '" + array[i]["idle_count"] + "', ";
          sql += "shutdown_time = '" + array[i]["shutdown_time"] + "', shutdown_count = '" + array[i]["shutdown_count"] + "', ";
          sql += "off_time = '" + array[i]["off_time"] + "', off_count = '" + array[i]["off_count"] + "' ";
          sql += "where MachineName = '" + array[i]["MachineName"] + "'";
          await db_util.query(sql);
        }
      }
    }
    array = null;
    return temp;
  }
  catch (error) {
    console.log('StatisticUtilization exception: ' + error.message);
    array = null;
    return temp;
  }
}

//NOUSE
app.post('/QueryCncTime', async (req, res) => {
  if (req.body.starttime != undefined) {
    if (req.body.starttime < '2020-06-01 08:00:00') {
      //console.log('QueryCncTime starttime error: ' + req.body.starttime + ' from ' + req.ip);
      res.status(404);
      res.end();
      return;
    }
  }
  let date = new Date();
  let cost_time = date.getTime();
  console.log('QueryCncTime from ' + req.ip + ' on ' + date.toLocaleString());
  let array = new Array();
  let arrIndex = {};
  let MachineName = "";
  //if( req.body.MachineName != undefined )
  //  MachineName = req.body.MachineName;
  for (let i = 0; i < g_cncInfo.length; i++) {
    if (MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName)
      continue;
    let json = {};
    json["id"] = g_cncInfo[i].id;
    json["name"] = g_cncInfo[i].name;
    json["MachineName"] = g_cncInfo[i].MachineName;
    json["MachineModel"] = g_cncInfo[i].MachineModel;
    json["MachineSN"] = g_cncInfo[i].MachineSN;
    json["run_time"] = 0;
    json["idle_time"] = 0;
    json["shutdown_time"] = 0;
    json["off_time"] = 0;
    json["total_time"] = 0;
    json["last_time"] = 0;
    json["last_mode"] = "";
    json["last_id"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }

  let starttime = 0;
  let month_jiadonglv = false;
  if (req.body.mode != "hour") {
    date.setTime(Date.parse(req.body.starttime));
    if (date.getDate() == 1 && date.getHours() == 0) // 获取当月稼动率时才用
    {
      month_jiadonglv = true;
      let month = getMonthDayTime(date);
      let sql = "select * from currentmonth where month = '" + month + "'";
      let suc2 = await db_util.query(sql);
      for (let i = 0; i < suc2.length; i++) {
        let index = arrIndex[suc2[i].MachineName];
        if (isNaN(index)) // total
        {
          starttime = parseInt(suc2[i].last_time);
          continue;
        }
        array[index]["run_time"] = parseInt(suc2[i].run_time);
        array[index]["idle_time"] = parseInt(suc2[i].idle_time);
        array[index]["shutdown_time"] = parseInt(suc2[i].shutdown_time);
        array[index]["off_time"] = parseInt(suc2[i].off_time);
        array[index]["total_time"] = parseInt(suc2[i].total_time);
        array[index]["last_time"] = parseInt(suc2[i].last_time);
        array[index]["last_mode"] = suc2[i].last_mode;
        array[index]["last_id"] = parseInt(suc2[i].last_id);
        if (starttime < array[index]["last_time"])
          starttime = array[index]["last_time"];
      }
      suc2 = null;
    }
  }

  let sql = "select id, MachineName, Time, Operation_Mode from cncdata";
  let msg = "QueryCncTime starttime = " + req.body.starttime;
  if (starttime > 0)
    sql += " where Time >= '" + starttime + "'";
  else
    sql += " where fmtTime >= '" + req.body.starttime + "'";
  if (req.body.endtime != undefined) {
    msg += ", endtime = " + req.body.endtime;
    sql += " and fmtTime < '" + req.body.endtime + "'";
  }
  if (MachineName.length > 0) {
    msg += ", cnc = " + MachineName;
    sql += " and MachineName = '" + MachineName + "'";
  }
  if (req.body.lastID != undefined) {
    sql += " and id <= '" + req.body.lastID + "'";
  }
  if (req.body.mode != undefined) {
    msg += ", mode = " + req.body.mode;
  }
  sql += " ORDER BY Time ASC";
  if (month_jiadonglv == true && msg.length > 0) {
    date.setTime(cost_time);
    console.log(msg + ' on ' + getMonthDayTime(date, 1, 1) + ' from ' + req.ip);
  }
  //console.log('QueryCncTime: ' + sql.substr(64) + ' on ' + cost_time);
  try {
    let suc = await db_util.query(sql);
    let update = false;
    let endtime = 0;
    let spantime = 0;
    if (req.body.starttime != undefined) {
      if (starttime == 0)
        starttime = Date.parse(req.body.starttime);
    }
    else if (suc.length > 0) {
      starttime = parseInt(suc[0].Time);
    }
    if (req.body.endtime != undefined) {
      endtime = Date.parse(req.body.endtime);
    }
    else if (suc.length > 0) {
      endtime = parseInt(suc[suc.length - 1].Time);
    }
    else {
      endtime = Date.now();
    }
    if (month_jiadonglv == true && suc.length > 0) {
      spantime = await CalcHolidayTime(Date.parse(req.body.starttime), endtime, null, 1);
      let tempTime = dotFixed(spantime / 3600000);
      if (suc.length > 1)
        console.log('当月稼动率统计新增记录条数：' + suc.length + '，最新ID：' + suc[suc.length - 1].id + '，周日及假期：' + tempTime + '小时/台');
      else
        console.log('当月稼动率统计，最新ID：' + suc[suc.length - 1].id + '，周日及假期：' + tempTime + '小时/台');
    }

    let flag = false;
    if (req.body.mode == "hour") {
      flag = true; // 按小时分段计算
      if ((endtime - starttime) < 3600001) // 只有一个小时，取消
        flag = false;
      else if (suc.length == 0)
        flag = false;
    }
    let total_run_time = 0; // 单位是毫秒
    let total_all_time = 0; // 单位是秒
    let total_idle_time = 0;
    let total_shutdown_time = 0;
    let total_off_time = 0;
    let total_total_time = 0; // ms
    for (let i = 0; i < array.length; i++) {
      let on_time = 0; // 除关机以外的时间
      let run_time = 0;
      let run_start = 0;
      let run_end = 0;
      let idle_time = 0;
      let idle_start = 0;
      let idle_end = 0;
      let shutdown_time = 0;
      let shutdown_start = 0;
      let shutdown_end = 0;
      let last_time = 0;
      let last_mode = "";
      let last_id = 0;
      let currentTime = 0;
      let flag_starttime = 0;
      let flag_endtime = 0;
      let temp = new Array();
      if (flag) {
        flag_starttime = starttime;
        flag_endtime = flag_starttime + 3600 * 1000;
        if (suc.length > 0) {
          while (flag_endtime < suc[0].Time) {
            let json = {};
            date.setTime(flag_starttime);
            json["date"] = date.toLocaleDateString();
            json["hour"] = date.getHours();
            json["rate"] = 0;
            temp.push(json);
            flag_starttime += 3600000;
            flag_endtime += 3600000;
          }
        }
      }
      else {
        last_time = array[i].last_time;
        last_mode = array[i].last_mode;
        last_id = array[i].last_id;
        if (last_mode == "Run")
          run_start = last_time;
        else if (last_mode == "Idle")
          idle_start = last_time;
        else if (last_mode == "Shutdown")
          shutdown_start = last_time;
      }

      while (true) {
        let machine_starttime = array[i].last_time;
        if (suc.length == 0)
          machine_starttime = 0;
        for (let k = 0; k < suc.length; k++) {
          if (array[i].MachineName != suc[k].MachineName)
            continue;
          if (flag) {
            if (suc[k].Time < flag_starttime)
              continue;
            else if (suc[k].Time >= flag_endtime)
              break;
          }
          currentTime = parseInt(suc[k].Time);
          if (machine_starttime == 0)
            machine_starttime = currentTime;
          // 判断是否有关机过程
          if (last_time > 0 && (currentTime - last_time) > g_nOffTime) // 间隔时间大于10分钟
          {
            //console.log(array[i].name + '关机，从' + last_time + '到' + currentTime + ', 时长：' + (currentTime - last_time));
            if (last_mode == "Run" && run_start > 0) {
              run_time += (last_time - run_start);
            }
            if (last_mode == "Idle" && idle_start > 0) {
              idle_time += (last_time - idle_start);
            }
            if (last_mode == "Shutdown" && shutdown_start > 0) {
              shutdown_time += (last_time - shutdown_start);
            }
            run_start = 0;
            idle_start = 0;
            shutdown_start = 0;
          }
          last_time = currentTime;
          last_mode = suc[k].Operation_Mode;
          last_id = parseInt(suc[k].id);

          // 计算运行时间
          run_end = currentTime;
          if (suc[k].Operation_Mode == "Run") {
            if (run_start == 0)
              run_start = run_end;
          }
          else if (run_start > 0) {
            run_time += (run_end - run_start);
            run_start = 0;
            run_end = 0;
          }

          // 计算等待时间
          idle_end = currentTime;
          if (suc[k].Operation_Mode == "Idle") {
            if (idle_start == 0)
              idle_start = idle_end;
          }
          else if (idle_start > 0) {
            idle_time += (idle_end - idle_start);
            idle_start = 0;
            idle_end = 0;
          }

          // 计算故障时间
          shutdown_end = currentTime;
          if (suc[k].Operation_Mode == "Shutdown") {
            if (shutdown_start == 0)
              shutdown_start = shutdown_end;
          }
          else if (shutdown_start > 0) {
            shutdown_time += (shutdown_end - shutdown_start);
            shutdown_start = 0;
            shutdown_end = 0;
          }
        }
        if (run_start > 0) {
          if (run_end > run_start)
            run_time += (run_end - run_start);
          //else
          //  console.log(array[i].MachineName + ' run_end=' + run_end + ', run_start=' + run_start);
        }
        if (idle_start > 0) {
          if (idle_end > idle_start)
            idle_time += (idle_end - idle_start);
          //else
          //  console.log(array[i].MachineName + ' idle_end=' + idle_end + ', idle_start=' + idle_start);
        }
        if (shutdown_start > 0) {
          if (shutdown_end > shutdown_start)
            shutdown_time += (shutdown_end - shutdown_start);
          //else
          //  console.log(array[i].MachineName + ' shutdown_end=' + shutdown_end + ', shutdown_start=' + shutdown_start);
        }

        if (flag) {
          let json = {};
          date.setTime(flag_starttime);
          json["date"] = date.toLocaleDateString();
          json["hour"] = date.getHours();
          run_time /= 1000; // 由毫秒转成秒
          total_run_time += run_time;
          if ((flag_starttime + 3600 * 1000) > suc[suc.length - 1].Time) {
            let gap = (suc[suc.length - 1].Time - flag_starttime) / 1000;
            json["rate"] = parseInt(0.5 + run_time * 100 / gap);
            if (json["rate"] > 100)
              json["rate"] = 100;
            total_all_time += gap;
          }
          else {
            run_time += 18; // 四舍五入
            if (run_time > 3600)
              run_time = 3600;
            json["rate"] = parseInt(run_time / 36);
            total_all_time += 3600;
          }
          temp.push(json);
          flag_starttime = flag_endtime;
          flag_endtime = flag_starttime + 3600 * 1000;
          if (flag_starttime > suc[suc.length - 1].Time) {
            break;
          }
          run_time = 0;
          run_start = 0;
          run_end = 0;
          idle_time = 0;
          idle_start = 0;
          idle_end = 0;
          shutdown_time = 0;
          shutdown_start = 0;
          shutdown_end = 0;
          last_time = 0;
          last_mode = "";
        }
        else {
          // 计算关机时间
          let total_time = endtime - starttime;
          if (suc.length > 0)
            total_time = last_time - machine_starttime;
          if (total_time < 0)
            total_time = 10;
          //if( month_jiadonglv == true )
          //  console.log('****** ' + array[i].MachineName + ' 已存总时长' + array[i].total_time + '，新增时长' + total_time + '，已存运行时间' + array[i].run_time + '，新增运行时间' + run_time);
          total_time += array[i].total_time;
          run_time += array[i].run_time;
          idle_time += array[i].idle_time;
          shutdown_time += array[i].shutdown_time;
          on_time = run_time + idle_time + shutdown_time;
          let off_time = total_time - on_time;
          if (endtime > starttime && req.body.mode != "hour" && req.body.starttime != undefined) {
            date.setTime(Date.parse(req.body.starttime));
            if (month_jiadonglv == true) // 获取当月稼动率时才用
            {
              let month = getMonthDayTime(date);
              sql = "select * from currentmonth where month = '" + month + "' and MachineName = '" + array[i].MachineName + "'";
              let suc3 = await db_util.query(sql);
              if (suc3.length > 0) {
                sql = "update currentmonth set run_time = '" + run_time + "', idle_time = '" + idle_time + "', ";
                sql += "shutdown_time = '" + shutdown_time + "', off_time = '" + off_time + "', ";
                sql += "total_time = '" + total_time + "', last_time = '" + last_time + "', ";
                sql += "last_id = '" + last_id + "', ";
                sql += "last_mode = '" + last_mode + "' ";
                sql += "where month = '" + month + "' and MachineName = '" + array[i].MachineName + "'";
              }
              else {
                sql = "insert into currentmonth (month, MachineName, run_time, idle_time, shutdown_time, off_time, total_time, last_time, last_id, last_mode) ";
                sql += "values ('" + month + "', '" + array[i].MachineName + "', '" + run_time + "', ";
                sql += "'" + idle_time + "', '" + shutdown_time + "', '" + off_time + "', '" + total_time + "', "
                sql += "'" + last_time + "', '" + last_id + "', '" + last_mode + "')";
              }
              await db_util.query(sql);
            }
          }
          array[i]["run_time"] = parseInt(run_time / 1000);
          array[i]["idle_time"] = parseInt(idle_time / 1000);
          array[i]["shutdown_time"] = parseInt(shutdown_time / 1000);
          array[i]["off_time"] = parseInt(off_time / 1000);
          array[i]["total_time"] = parseInt(total_time / 1000);

          let json = {};
          json["hour"] = "";
          json["rate"] = parseInt(run_time * 100 / (total_time + spantime) + 0.5);
          if (isNaN(json["rate"]))
            json["rate"] = 0;
          if (json["rate"] < 0) {
            console.log(array[i]['MachineName'], '数据异常，稼动率小于零，runtime:', run_time, 'total_time:', total_time, 'spantime:', dotFixed(spantime / 3600000), json['rate']);
            update = true;
            json["rate"] = 0;
          }
          else if (json["rate"] > 100) {
            console.log(array[i]['MachineName'], '数据异常，稼动率超过100，runtime:', run_time, 'total_time:', total_time, 'spantime:', dotFixed(spantime / 3600000), json['rate']);
            update = true;
            json["rate"] = 100;
          }
          temp.push(json);
          total_run_time += run_time;
          total_all_time += total_time / 1000;
          total_idle_time += idle_time;
          total_shutdown_time += shutdown_time;
          total_off_time += off_time;
          total_total_time += total_time;
          break;
        }
      }
      if (flag) {
        if (req.body.endtime != undefined)
          endtime = Date.parse(req.body.endtime);
        else
          endtime = Date.now();
        while (flag_starttime < endtime) {
          let json = {};
          date.setTime(flag_starttime);
          json["date"] = date.toLocaleDateString();
          json["hour"] = date.getHours();
          json["rate"] = 0;
          temp.push(json);
          flag_starttime += 3600000;
        }
      }
      array[i]["jiadonglv"] = temp;
    }

    if (month_jiadonglv == true && suc.length > 1) // 获取当月稼动率时才用
    {
      date.setTime(Date.parse(req.body.starttime));
      let month = getMonthDayTime(date);
      sql = "select * from currentmonth where month = '" + month + "' and MachineName = 'total'";
      let suc4 = await db_util.query(sql);
      if (suc4.length > 0) {
        sql = "update currentmonth set run_time = '" + total_run_time + "', idle_time = '" + total_idle_time + "', ";
        sql += "shutdown_time = '" + total_shutdown_time + "', off_time = '" + total_off_time + "', ";
        sql += "total_time = '" + total_total_time + "', last_time = '" + suc[suc.length - 1].Time + "', ";
        sql += "last_id = '" + suc[suc.length - 1].id + "', ";
        sql += "last_mode = '" + suc[suc.length - 1].Operation_Mode + "' ";
        sql += "where month = '" + month + "' and MachineName = 'total'";
      }
      else {
        sql = "insert into currentmonth (month, MachineName, run_time, idle_time, shutdown_time, off_time, total_time, last_time, last_id, last_mode) ";
        sql += "values ('" + month + "', 'total', '" + total_run_time + "', ";
        sql += "'" + total_idle_time + "', '" + total_shutdown_time + "', '" + total_off_time + "', '" + total_total_time + "', "
        sql += "'" + suc[suc.length - 1].Time + "', '" + suc[suc.length - 1].id + "', '" + suc[suc.length - 1].Operation_Mode + "')";
      }
      await db_util.query(sql);

      cost_time = Date.now() - cost_time;
      sql = "当月稼动率统计 ";
      spantime = 0;
      let device_count = 0;
      for (let i = 0; i < array.length; i++) {
        on_time = array[i].run_time + array[i].idle_time + array[i].shutdown_time;
        if (on_time < 1000)
          continue;
        device_count++;
        spantime += array[i]["jiadonglv"][0].rate;
        //console.log('****** ' + array[i].MachineName + ' 总时长：' + array[i].total_time + '，运行时间：' + array[i].run_time + '，稼动率：' + array[i]["jiadonglv"][0].rate);
      }
      if (device_count > 0)
        spantime /= device_count;
      spantime = dotFixed(spantime, 3);
      console.log(sql + '运行时间：' + total_run_time + '，总时长：' + parseInt(total_all_time) + '，平均稼动率：' + spantime + '，有效设备数目：' + device_count);
      if (suc.length > 0)
        console.log('QueryCncTime cost time: ' + cost_time + 'ms, 最后一笔记录时间：' + suc[suc.length - 1].Time);
      else
        console.log('QueryCncTime cost time: ' + cost_time + 'ms');
    }
    else if (month_jiadonglv == true && suc.length < 2) {
      cost_time = Date.now() - cost_time;
      console.log('当月稼动率统计 没有更新，cost time: ' + cost_time + 'ms');
    }
    suc = null;
    if (update) {
      date.setTime(Date.now());
      //await ResetCncMonthData(date);
      console.log('稼动率数据异常，清除cncmonth和currentmonth表中' + month + '月份的数据吗？');
    }
    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (err) {
    res.status(200);
    res.json({ "result": "error", "order": array, "description": err.message });
  }
})

async function setTime(date, hours, minutes, seconds, milliseconds) {
  date.setHours(hours);
  if (minutes != undefined)
    date.setMinutes(minutes);
  else
    date.setMinutes(0);
  if (seconds != undefined)
    date.setSeconds(seconds);
  else
    date.setSeconds(0);
  if (milliseconds != undefined)
    date.setMilliseconds(milliseconds);
  else
    date.setMilliseconds(0);
}

async function CalcHolidayTime(starttime, endtime, noSunday, calcStarttime) {
  let dt = new Date();
  let currentTime = starttime;
  let st = 0, et = 0, spantime = 0; // 单位：毫秒
  let includeSunday = true;
  if (noSunday != undefined)
    includeSunday = false;
  let sql = "select * from cnctime where starttime != 'null'";
  let suc3 = await db_util.query(sql);
  if (calcStarttime != undefined) {
    dt.setTime(starttime);
    dt.setDate(1);
    setTime(dt, 0);
    sql = "select id, Time from cncdata where Time >= '" + dt.getTime() + "' ORDER BY Time ASC LIMIT 1";
    let succ4 = await db_util.query(sql);
    if (succ4.length > 0) {
      starttime = parseInt(succ4[0].Time);
      currentTime = starttime;
    }
  }
  while (currentTime < endtime) {
    dt.setTime(currentTime);
    if (dt.getDay() == 0) // 周日
    {
      setTime(dt, 8);
      st = dt.getTime();
      et = st + 24 * 3600 * 1000;
      if (starttime >= et || endtime <= st) {
        // 与周日没有交集
      }
      else if (includeSunday) {
        if (et <= endtime)
          spantime -= 24 * 3600 * 1000; // 周日从8点到下周一8点统一扣除24小时
        else
          spantime -= (endtime - st);
        /*var flag = true;
        // 看看此周日是否被设置成休假或加班
        for(let i=0; i<suc3.length; i++)
        {
          var st2 = parseInt(suc3[i].starttime);
          var et2 = parseInt(suc3[i].endtime);
          if( suc3[i].starttime.indexOf('-') > 0 )
            st2 = Date.parse(suc3[i].starttime);
          if( suc3[i].endtime.indexOf('-') > 0 )
            et2 = Date.parse(suc3[i].endtime);
          if( st >= et2 || et <= st2 )
          {
            // 此周日和设置时间没有交集
          }
          else
          {
            //flag = false;
            if( st < st2 )
            {
              if( et <= et2 )
              {
                spantime += (et - st2);
              }
              else
              {
                spantime += (et2 - st2);
              }
            }
            else
            {
              if( et <= et2 )
              {
                spantime += (et - st);
              }
              else
              {
                spantime += (et2 - st);
              }
            }
          }
        }
        if( flag )
        {
          if( starttime < st )
          {
            if( endtime <= et )
            {
              spantime -= (endtime - st);
            }
            else
            {
              spantime -= (et - st);
            }
          }
          else
          {
            if( endtime <= et )
            {
              spantime -= (endtime - starttime);
            }
            else
            {
              spantime -= (et - starttime);
            }
          }
        }*/
      }
      currentTime += 7 * 24 * 3600000;
    }
    else {
      currentTime += (7 - dt.getDay()) * 24 * 3600000;
    }
  }
  for (let i = 0; i < suc3.length; i++) {
    st = parseInt(suc3[i].starttime);
    et = parseInt(suc3[i].endtime);
    if (suc3[i].starttime.indexOf('-') > 0)
      st = Date.parse(suc3[i].starttime);
    if (suc3[i].endtime.indexOf('-') > 0)
      et = Date.parse(suc3[i].endtime);
    if (starttime >= et || endtime <= st) {
      // 没有交集
    }
    else {
      let offset = 0;
      if (starttime < st) {
        if (endtime <= et) {
          offset = endtime - st;
        }
        else {
          offset = et - st;
        }
      }
      else {
        if (endtime <= et) {
          offset = endtime - starttime;
        }
        else {
          offset = et - starttime;
        }
      }
      if (suc3[i].status == "0") // 休假
      {
        spantime -= offset;
      }
      else {
        spantime += offset;
      }
    }
  }
  /*dt.setTime(starttime);
  sql = "计算假期：" + getMonthDayTime(dt, 1) + " ~ ";
  dt.setTime(endtime);
  sql += getMonthDayTime(dt, 1);
  sql += "，包括加班（+）、休假/周日（-），时长：" + spantime/3600000;
  console.log(sql);*/
  return spantime;
}

async function StatisticOee(body_MachineName, body_starttime, body_endtime) {
  //let date = new Date();
  let ret_json = {};
  try {
    let array = await StatisticUtilization(body_MachineName, body_starttime, body_endtime);
    let starttime = 0;
    let endtime = 0;
    let run_time = 0;
    let total_time = 0;
    let last_id = 0;
    let device_count = 0;
    for (let i = 0; i < array.length; i++) {
      let on_time = array[i]["run_time"] + array[i]["idle_time"] + array[i]["shutdown_time"];
      if (on_time < 1000)
        continue;
      if (starttime == 0)
        starttime = array[i]["start_time"];
      else if (array[i]["start_time"] < starttime)
        starttime = array[i]["start_time"];
      if (array[i]["last_time"] > endtime)
        endtime = array[i]["last_time"];
      run_time += array[i]["run_time"];
      total_time += (array[i]["last_time"] - array[i]["start_time"]);
      last_id = array[i]["lastID"];
      device_count++;
    }
    starttime = Date.parse(body_starttime); // 这样就和按周、月统计的结果相同，否则在周日中计算扣除时间就有差别，如开始时间是10点则只扣22个小时

    // 开始计算OEE
    ret_json["run_time"] = run_time;
    ret_json["total_time"] = total_time;
    ret_json["last_time"] = endtime;
    ret_json["last_id"] = last_id;
    run_time /= 36000; // (ms --> hour)*100
    total_time /= 3600000; //  毫秒转成小时
    let oee = parseInt(run_time / total_time + 0.5);
    if (isNaN(oee))
      oee = 0;
    console.log('StatistocOee oee: ' + run_time + '/' + total_time + ' = ' + oee + '，有效设备数目：' + device_count);
    if (oee > 100)
      oee = 100;
    let oee15 = 0;
    let spantime = await CalcHolidayTime(starttime, endtime); // 单位：毫秒
    total_time += (spantime * device_count / 3600000);
    if ((total_time * 3600) < 1) // 如果总时间小于1秒，保证分母不为0
      total_time = 1 / 3600;
    oee15 = parseInt(run_time / total_time + 0.5);
    if (isNaN(oee15))
      oee15 = 0;
    console.log('StatistocOee oee1.5: ' + run_time + '/' + total_time + ' = ' + oee15);
    if (oee15 > 100)
      oee15 = 100;
    ret_json["result"] = "ok";
    ret_json["oee1"] = oee;
    ret_json["oee15"] = oee15;
    ret_json["total_time_15"] = parseInt(total_time * 3600000);
    if (body_MachineName != undefined) {
      let arrInfo = new Array();
      for (let i = 0; i < array.length; i++) {
        let json = {};
        json["run_time"] = array[i]["run_time"];
        json["total_time"] = array[i]["total_time"];
        json["last_time"] = array[i]["last_time"];
        json["last_id"] = array[i]["last_id"];
        total_time = json["total_time"] + spantime;
        json["total_time_15"] = total_time;
        if (total_time < 10000)
          total_time = 10000;
        json["oee1"] = parseInt(json["run_time"] / json["total_time"] + 0.5);
        json["oee15"] = parseInt(json["run_time"] / total_time + 0.5);
        if (json["oee1"] > 100)
          json["oee1"] = 100;
        if (json["oee15"] > 100)
          json["oee15"] = 100;
        arrInfo.push(json);
      }
      ret_json["order"] = arrInfo;
    }
    suc = null;
    return ret_json;
  }
  catch (error) {
    console.log('StatisticOee exception: ' + error.message);
    ret_json["result"] = "error";
    ret_json["oee1"] = 0;
    ret_json["oee15"] = 0;
    ret_json["description"] = error.message;
    return ret_json;
  }
}

//NOUSE
app.post('/QueryCncOee', async (req, res) => {
  let ret = await StatisticOee(req.body.MachineName, req.body.starttime, req.body.endtime);
  res.status(200);
  res.json(ret);
})

//NOUSE
app.post('/QueryCncOeeHour', function (req, res) {
  if (req.body.starttime == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set starttime parameter" });
    return;
  }
  else {
    if (req.body.starttime < '2020-06-01 08:00:000') {
      //console.log('QueryCncOeeHour starttime error: ' + req.body.starttime + ' from ' + req.ip);
      res.status(404);
      res.end();
      return;
    }
  }
  let date = new Date();
  let cost_time = date.getTime();
  //console.log('QueryCncOee from ' + req.ip + ' on ' + date.toLocaleString()); 
  let total_run_time = 0;
  let array = new Array();
  let arrIndex = {};
  let MachineName = "";
  if (req.body.MachineName != undefined)
    MachineName = req.body.MachineName;
  for (let i = 0; i < g_cncInfo.length; i++) {
    if (MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName)
      continue;
    let json = {};
    json["name"] = g_cncInfo[i].name;
    json["start_time"] = 0; // 第一次记录的时间
    json["last_time"] = 0; // 上一次记录的时间，用于判断是否关机
    json["last_mode"] = "";
    json["run_time"] = 0;
    json["run_start"] = 0;
    json["run_end"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }

  let flag = false;
  let sql = "select MachineName, Time, fmtTime, Operation_Mode from cncdata";
  if (req.body.starttime != undefined) {
    if (flag) {
      sql += " and fmtTime >= '" + req.body.starttime + "'";
    }
    else {
      flag = true;
      sql += " where fmtTime >= '" + req.body.starttime + "'";
    }
  }
  if (req.body.endtime != undefined) {
    if (flag) {
      sql += " and fmtTime < '" + req.body.endtime + "'";
    }
    else {
      flag = true;
      sql += " where fmtTime < '" + req.body.endtime + "'";
    }
  }
  if (MachineName.length > 0) {
    if (flag) {
      sql += " and MachineName = '" + MachineName + "'";
    }
    else {
      flag = true;
      sql += " where MachineName = '" + MachineName + "'";
    }
  }
  sql += " ORDER BY Time ASC";
  //console.log('QueryCncOeeHour: ' + sql);
  db_util.ExecuteSQL(sql, null,
    (suc) => {
      let starttime = Date.parse(req.body.starttime); // 起始时间要不要从实际数据时间算起？？？
      let spantime = 3600 * 1000;
      let endtime = starttime + spantime;
      if (suc.length > 0) {
        while (endtime <= suc[0].Time) {
          starttime += spantime;
          endtime += spantime;
        }
        if (starttime < suc[0].Time) {
          starttime = parseInt(suc[0].Time);
          spantime = endtime - starttime;
        }
      }
      let temp = new Array();
      let index = -1;
      let currentTime = 0;
      for (let k = 0; k < suc.length; k++) {
        index = arrIndex[suc[k].MachineName];
        if (isNaN(index))
          continue;
        currentTime = parseInt(suc[k].Time);
        if (array[index]["start_time"] == 0)
          array[index]["start_time"] = currentTime;
        if (currentTime < endtime) {
          // 判断是否有关机过程
          if (array[index]["last_time"] > 0 && (currentTime - array[index]["last_time"]) > g_nOffTime) // 间隔时间大于10分钟
          {
            //console.log(array[index].name + '关机，从' + array[index]["last_time"] + '到' + currentTime + ', 时长：' + parseInt((currentTime - array[index]["last_time"])));
            if (array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0) {
              array[index]["run_time"] += (array[index]["last_time"] - array[index]["run_start"]);
            }
            array[index]["run_start"] = 0;
          }
          array[index]["last_time"] = currentTime;
          array[index]["last_mode"] = suc[k].Operation_Mode;

          // 计算运行时间
          array[index]["run_end"] = currentTime;
          if (suc[k].Operation_Mode == "Run") {
            if (array[index]["run_start"] == 0)
              array[index]["run_start"] = currentTime;
          }
          else if (array[index]["run_start"] > 0) {
            array[index]["run_time"] += (currentTime - array[index]["run_start"]);
            array[index]["run_start"] = 0;
            array[index]["run_end"] = 0;
          }
        }
        else {
          let run_time = 0;
          let device_count = 0;
          for (let i = 0; i < array.length; i++) {
            if (array[i]["last_mode"] == "Run" && array[i]["run_start"] > 0) {
              array[i]["run_time"] += (array[i]["last_time"] - array[i]["run_start"]);
            }
            run_time += array[i]["run_time"];
            if (array[i]["run_time"] >= 1000)
              device_count++;
            array[i]["run_time"] = 0;
            array[i]["run_start"] = 0;
            array[i]["run_end"] = 0;
          }
          total_run_time += run_time;
          if (device_count > 0)
            run_time /= device_count;
          if (run_time > spantime)
            run_time = spantime;
          run_time *= 100;
          run_time /= spantime;
          run_time += 0.5; // 四舍五入
          let json = {};
          date.setTime(parseInt(starttime));
          json["hour"] = date.getHours();
          json["oee"] = parseInt(run_time);
          json["oee15"] = parseInt(run_time);
          if (json["oee"] > 100)
            json["oee"] = 100;
          if (json["oee15"] > 100)
            json["oee15"] = 100;
          temp.push(json);

          k--;
          spantime = 3600 * 1000;
          starttime = endtime;
          endtime = starttime + spantime;
        }
      }
      if (suc.length > 0 && suc[suc.length - 1].Time < endtime) {
        let run_time = 0;
        let total_time = 0;
        let device_count = 0;
        for (let i = 0; i < array.length; i++) {
          if (array[i]["last_mode"] == "Run" && array[i]["run_start"] > 0) {
            array[i]["run_time"] += (array[i]["last_time"] - array[i]["run_start"]);
          }
          run_time += array[i]["run_time"];
          total_time += (array[i]["last_time"] - array[i]["start_time"]);
          if (array[i]["run_time"] > 0)
            device_count++;
        }
        total_run_time += run_time;
        if (device_count > 0)
          run_time /= device_count;
        if ((suc[suc.length - 1].Time - starttime) < spantime) {
          spantime = suc[suc.length - 1].Time - starttime;
          if (spantime < 1000)
            spantime = 1000; // 防止分母为0
        }
        if (run_time > spantime)
          run_time = spantime;
        run_time *= 100;
        run_time /= spantime;
        run_time += 0.5; // 四舍五入
        let json = {};
        date.setTime(parseInt(starttime));
        json["hour"] = date.getHours();
        json["oee"] = parseInt(run_time);
        json["oee15"] = parseInt(run_time);
        if (json["oee"] > 100)
          json["oee"] = 100;
        if (json["oee15"] > 100)
          json["oee15"] = 100;
        temp.push(json);
      }
      if (suc.length > 0) {
        if (req.body.endtime == undefined) {
          spantime = 3600 * 1000;
          starttime = endtime;
          currentTime = starttime + (12 - temp.length) * spantime;
          endtime = Date.now();
          if (endtime > currentTime)
            endtime = currentTime;
          while (starttime < endtime) {
            let json = {};
            date.setTime(parseInt(starttime));
            json["hour"] = date.getHours();
            json["oee"] = 0;
            json["oee15"] = 0;
            temp.push(json);
            starttime += spantime;
          }
        }
      }
      else {
        spantime = 3600 * 1000;
        starttime = Date.parse(req.body.starttime);
        currentTime = starttime + (12 - temp.length) * spantime;
        endtime = Date.now();
        if (endtime > currentTime)
          endtime = currentTime;
        while (starttime < endtime) {
          let json = {};
          date.setTime(parseInt(starttime));
          json["hour"] = date.getHours();
          json["oee"] = 0;
          json["oee15"] = 0;
          temp.push(json);
          starttime += spantime;
        }
        if (temp.length == 0) {
          let json = {};
          date.setTime(starttime);
          json["hour"] = date.getHours();
          json["oee"] = 0;
          json["oee15"] = 0;
          temp.push(json);
          console.log('QueryCncOeeHour: find nothing from ' + getMonthDayTime(date, 1, 1));
        }
      }
      /*if( suc.length > 0 )
      {
        cost_time = Date.now() - cost_time;
        console.log('QueryCncOeeHour 运行时间:' + total_run_time + '，总时长:' + total_time);
        console.log('QueryCncOeeHour cost time: ' + cost_time + 'ms, 开始记录时间：' + suc[0].Time + '，最后记录时间：' + suc[suc.length-1].Time);
      }*/
      suc = null;
      res.status(200);
      res.json({ "result": "ok", "oee": temp });
    },
    (err) => {
      res.status(200);
      res.json({ "result": "error", "description": err.message });
    }
  );
})

function getMonthDayTime2(utc_time, more) {
  let date = new Date(utc_time);
  return getMonthDayTime(date, 1, 1, more);
}

function getMonthDayTime(date, day, time, more) {
  if (day == 2) // 只需要日期（MM:DD）
  {
    let i = date.getDate();
    let k = date.getMonth() + 1;
    let ret = "";
    if (k < 10)
      ret += "0";
    ret += k.toString();
    ret += "-";
    if (i < 10)
      ret += "0";
    ret += i.toString();
    return ret;
  }
  if (time == 2) // 只需要时间（hh:mm）
  {
    let i = date.getHours();
    let k = date.getMinutes();
    let ret = "";
    if (i < 10)
      ret += "0";
    ret += i.toString();
    ret += ":";
    if (k < 10)
      ret += "0";
    ret += k.toString();
    if (more != undefined) {
      ret += ":";
      k = date.getSeconds();
      if (k < 10)
        ret += "0";
      ret += k.toString();
      if (more == 2) {
        ret += '.';
        i = date.getMilliseconds();
        if (i < 10)
          ret += '00';
        else if (i < 100)
          ret += '0';
        ret += i.toString();
      }
    }
    return ret;
  }
  let ret = date.getFullYear() + '-';
  if (date.getMonth() < 9)
    ret += '0';
  ret += (date.getMonth() + 1);
  if (day != undefined) {
    ret += '-';
    if (date.getDate() < 10)
      ret += '0';
    ret += date.getDate();
    if (time != undefined) {
      ret += ' ';
      if (date.getHours() < 10)
        ret += '0';
      ret += date.getHours();
      ret += ':';
      if (date.getMinutes() < 10)
        ret += '0';
      ret += date.getMinutes();
      ret += ':';
      if (date.getSeconds() < 10)
        ret += '0';
      ret += date.getSeconds();
      if (more != undefined) {
        ret += '.';
        let i = date.getMilliseconds();
        if (i < 10)
          ret += '00';
        else if (i < 100)
          ret += '0';
        ret += i.toString();
      }
    }
  }
  return ret;
}

function getYearWeek(time, weekonly) {
  let date = new Date(time);
  setTime(date, 0);
  let dt = new Date(date.getFullYear(), 0, 1);
  let d = Math.round((date.getTime() - dt.getTime()) / 86400000);
  let weeks = Math.ceil((d + dt.getDay() + 1) / 7);
  if (weekonly != undefined)
    return weeks;
  let ret = dt.getFullYear() + '-';
  if (weeks < 10)
    ret += '0';
  ret += weeks;
  return ret;
}

async function StatisticOeeWeek(body_MachineName, body_starttime, body_endtime) {
  let date = new Date();
  let cost_time = date.getTime();
  let array = new Array();
  let arrIndex = {};
  let MachineName = "";
  if (body_MachineName != undefined)
    MachineName = body_MachineName;
  for (let i = 0; i < g_cncInfo.length; i++) {
    if (MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName)
      continue;
    let json = {};
    json["start_time"] = 0; // 第一次记录的时间
    json["last_time"] = 0; // 上一次记录的时间，用于判断是否关机
    json["last_mode"] = "";
    json["run_time"] = 0;
    json["run_start"] = 0;
    json["run_end"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }

  let temp = new Array(); // 返回结果数组
  let flag = false;
  let starttime = Date.parse(body_starttime);
  let current_week = getYearWeek(date.getTime());
  date.setTime(starttime);
  if (date.getHours() != 0) {
    setTime(date, 0);
    starttime = date.getTime();
  }
  let sql = getYearWeek(starttime);
  if (sql < current_week) {
    try {
      let firsttime = 0;
      let suc4 = await db_util.query("select value from cncother where name = 'firsttime'");
      if (suc4.length > 0) {
        firsttime = parseInt(suc4[0].value);
      }
      else {
        let suc3 = await db_util.query("select Time, fmtTime from cncdata ORDER BY Time ASC LIMIT 1");
        if (suc3.length > 0) {
          firsttime = parseInt(suc3[0].Time);
          let sql2 = "insert into cncother (name, value) values('firsttime', '" + suc3[0].Time + "')";
          await db_util.query(sql2);
        }
      }
      if (firsttime > 0) {
        let week = getYearWeek(firsttime);
        let start_week = getYearWeek(starttime);
        while (start_week < week) {
          let json = {};
          json["year"] = date.getFullYear();
          json["week"] = getYearWeek(starttime, 1);
          json["oee"] = 0;
          json["oee15"] = 0;
          temp.push(json);
          starttime += 7 * 24 * 3600000;
          date.setTime(starttime);
          start_week = getYearWeek(starttime);
        }
        dt = null;
      }
      let suc2 = await db_util.query("select * from cncweek where name = '" + MachineName + "'");
      for (let i = 0; i < suc2.length; i++) {
        if (suc2[i].week < sql)
          continue;
        else if (suc2[i].week >= current_week)
          break;
        if (suc2[i].week < current_week) {
          let json = {};
          json["year"] = date.getFullYear();
          json["week"] = getYearWeek(starttime, 1);
          json["oee"] = suc2[i].oee;
          json["oee15"] = suc2[i].oee15;
          temp.push(json);
          starttime += 7 * 24 * 3600000;
          date.setTime(starttime);
          sql = getYearWeek(starttime);
        }
      }
      let suc5 = await db_util.query("select Time, fmtTime from cncdata ORDER BY Time DESC LIMIT 1");
      if (suc5.length > 0) {
        let last_time = parseInt(suc5[0].Time);
        let week = getYearWeek(last_time);
        if (current_week > week)
          current_week = week;
        if (current_week <= sql) {
          starttime = date.getTime() - date.getDay() * 24 * 3600000;
          if (starttime > last_time) // 最后一周需要实时计算
          {
            date.setTime(last_time);
            setTime(date, 0);
            starttime = date.getTime() - date.getDay() * 24 * 3600000;
            last_time = getYearWeek(starttime, 1);
            for (let i = temp.length - 1; i >= 0; i--) {
              if (temp[i]["week"] == last_time) {
                temp.splice(i, 1);
                break;
              }
            }
          }
        }
      }
      suc2 = null;
    }
    catch (err) {
      console.log('query cncweek error: ' + err.message);
    }
  }
  date.setTime(cost_time);
  sql = getMonthDayTime(date, 1, 1);
  date.setTime(starttime);
  console.log('StatisticOeeWeek on ' + sql + ', ' + body_starttime + ' from ' + starttime + ' [' + getMonthDayTime(date, 1, 1) + ']');

  sql = "select id, MachineName, Time, Operation_Mode from cncdata";
  if (flag) {
    sql += " and Time >= '" + starttime + "'";
  }
  else {
    flag = true;
    sql += " where Time >= '" + starttime + "'";
  }
  let endtime_set = 0;
  if (body_endtime != undefined) {
    endtime_set = Date.parse(body_endtime);
    if (flag) {
      sql += " and Time < '" + endtime_set + "'";
    }
    else {
      flag = true;
      sql += " where Time < '" + endtime_set + "'";
    }
  }
  if (MachineName.length > 0) {
    if (flag) {
      sql += " and MachineName = '" + MachineName + "'";
    }
    else {
      flag = true;
      sql += " where MachineName = '" + MachineName + "'";
    }
  }
  sql += " ORDER BY Time ASC";
  console.log('StatisticOeeWeek: ' + sql);
  try {
    let suc = await db_util.query(sql);

    date.setTime(starttime);
    let dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
    let endtime = dt.getTime() + (7 - dt.getDay()) * 24 * 3600000;
    if (endtime_set > 0 && endtime > endtime_set)
      endtime = endtime_set;
    let spantime = endtime - starttime;

    let index = suc.length;
    let currentTime = 0;
    let first_time = 0; // 该周的第一个数据，和最后一个数据一起统计spantime
    let last_time = 0;
    let begin_time = 0;
    let week_begin = 0; // 如果一周的前几天请假，那么这几天的时间就无法计算进去了，所以加了这个变量来保存一个星期的开始
    if (suc.length > 0)
      begin_time = parseInt(suc[0].Time);
    for (let k = 0; k < suc.length; k++) {
      index = arrIndex[suc[k].MachineName];
      if (isNaN(index))
        continue;
      currentTime = parseInt(suc[k].Time);
      if (currentTime < endtime) {
        if (first_time == 0)
          first_time = currentTime;
        last_time = currentTime;
        if (array[index]["start_time"] == 0)
          array[index]["start_time"] = currentTime;
        // 判断是否有关机过程
        if (array[index]["last_time"] > 0 && (currentTime - array[index]["last_time"]) > g_nOffTime) // 间隔时间大于10分钟
        {
          //console.log(suc[k].MachineName + '关机，从' + array[index]["last_time"] + '到' + currentTime + ', 时长：' + parseInt((currentTime - array[index]["last_time"])));
          if (array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0) {
            array[index]["run_time"] += (array[index]["last_time"] - array[index]["run_start"]);
          }
          array[index]["run_start"] = 0;
        }
        array[index]["last_time"] = currentTime;
        array[index]["last_mode"] = suc[k].Operation_Mode;
        array[index]["last_id"] = parseInt(suc[k].id);

        // 计算运行时间
        array[index]["run_end"] = currentTime;
        if (suc[k].Operation_Mode == "Run") {
          if (array[index]["run_start"] == 0)
            array[index]["run_start"] = currentTime;
        }
        else if (array[index]["run_start"] > 0) {
          array[index]["run_time"] += (currentTime - array[index]["run_start"]);
          array[index]["run_start"] = 0;
          array[index]["run_end"] = 0;
        }
      }
      else // 到了下一周了
      {
        let run_time = 0;
        let total_time = 0;
        let device_count = 0;
        for (let i = 0; i < array.length; i++) {
          if (array[i]["last_time"] > 0 && (endtime - array[i]["last_time"]) > g_nOffTime) // 间隔时间大于10分钟
          {
            if (array[i]["last_mode"] == "Run" && array[i]["run_start"] > 0) {
              array[i]["run_time"] += (array[i]["last_time"] - array[i]["run_start"]);
            }
            array[i]["run_start"] = 0;
          }
          if (array[i]["run_start"] > 0) {
            array[i]["run_time"] += (endtime - array[i]["run_start"]);
          }
          if (array[i]["run_time"] < 1000)
            continue;
          run_time += array[i]["run_time"];
          if (week_begin > 0 && (array[i]["start_time"] - week_begin) > g_nOffTime) {
            total_time += (array[i]["last_time"] - week_begin);
          }
          else {
            total_time += (array[i]["last_time"] - array[i]["start_time"]);
          }
          device_count++;
        }

        let run_time2 = run_time;
        if (total_time < run_time)
          total_time = run_time;
        spantime = total_time;
        date.setTime(starttime);
        let json = {};
        json["year"] = date.getFullYear();
        json["week"] = getYearWeek(starttime, 1);
        if (total_time < 1)
          json["oee"] = 0;
        else
          json["oee"] = parseInt(run_time * 100 / total_time + 0.5);
        console.log(getMonthDayTime(date, 1, 1) + ' ~ weekend');
        console.log('周稼动率统计 OEE运行时间：' + run_time + '，总时长：' + total_time + ', OEE = ' + json["oee"] + '，有效设备数目：' + device_count);
        run_time = run_time2;
        index = endtime;
        endtime = last_time;
        if (first_time == begin_time) {
          spantime = await CalcHolidayTime(first_time, last_time);
        }
        else if (week_begin > 0) {
          spantime = await CalcHolidayTime(week_begin, last_time);
        }
        else {
          spantime = await CalcHolidayTime(first_time, last_time, "noSunday");
          spantime -= 24 * 3600000; // 有可能周日没有数据，first_time不是从周日开始的，所以周日统一扣除24小时的时间
        }
        let spantime_1 = spantime;
        spantime *= device_count;
        spantime += total_time;
        if (spantime < run_time)
          spantime = run_time;
        json["oee15"] = parseInt(run_time * 100 / spantime + 0.5);
        if (json["oee"] > 100)
          json["oee"] = 100;
        if (json["oee15"] > 100)
          json["oee15"] = 100;
        console.log('周稼动率统计 OEE1.5运行时间：' + run_time + '，总时长：' + spantime + ', OEE1.5 = ' + json["oee15"]);
        temp.push(json);
        if (run_time > 0) {
          let week = getYearWeek(date.getTime());
          if (MachineName.length == 0) {
            sql = "select * from cncweek where week = '" + week + "' and length(name) = 0";
            let succ4 = await db_util.query(sql);
            if (succ4.length == 0)
              sql = "insert into cncweek (week, oee, oee15, run_time, total_time, total_time_15, last_time, last_id) values('" + week + "', '" + json["oee"] + "', '" + json["oee15"] + "', '" + run_time + "', '" + total_time + "', '" + spantime + "', '" + suc[k - 1].Time + "', '" + suc[k - 1].id + "')";
            else
              sql = "update cncweek set oee = '" + json["oee"] + "', oee15 = '" + json["oee15"] + "', run_time = '" + run_time + "', total_time = '" + total_time + "', total_time_15 = '" + spantime + "', last_time = '" + suc[k - 1].Time + "', last_id = '" + suc[k - 1].id + "' where week = '" + week + "' and length(name) = 0";
            await db_util.query(sql);
            succ4 = null;
          }
          for (let i = 0; i < array.length; i++) {
            let name = MachineName;
            if (name.length == 0)
              name = g_cncInfo[i].MachineName;
            run_time = array[i]["run_time"];
            if (week_begin > 0 && (array[i]["start_time"] - week_begin) > g_nOffTime)
              total_time = (array[i]["last_time"] - week_begin);
            else
              total_time = (array[i]["last_time"] - array[i]["start_time"]);
            spantime = spantime_1 + total_time;
            if (total_time < run_time)
              total_time = run_time;
            if (spantime < run_time)
              spantime = run_time;
            let oee = parseInt(run_time * 100 / total_time + 0.5);
            let oee15 = parseInt(run_time * 100 / spantime + 0.5);
            if (oee > 100)
              oee = 100;
            if (oee15 > 100)
              oee15 = 100;
            sql = "select * from cncweek where week = '" + week + "' and name = '" + name + "'";
            let succ4 = await db_util.query(sql);
            if (succ4.length == 0)
              sql = "insert into cncweek (week, name, oee, oee15, run_time, total_time, total_time_15, last_time, last_id) values('" + week + "', '" + name + "', '" + oee + "', '" + oee15 + "', '" + run_time + "', '" + total_time + "', '" + spantime + "', '" + array[i]["last_time"] + "', '" + array[i]["last_id"] + "')";
            else
              sql = "update cncweek set oee = '" + oee + "', oee15 = '" + oee15 + "', run_time = '" + run_time + "', total_time = '" + total_time + "', total_time_15 = '" + spantime + "', last_time = '" + array[i]["last_time"] + "', last_id = '" + array[i]["last_id"] + "' where week = '" + week + "' and name = '" + name + "'";
            await db_util.query(sql);
            succ4 = null;
          }
        }
        for (let i = 0; i < array.length; i++) {
          array[i]["run_time"] = 0;
          array[i]["run_start"] = 0;
          array[i]["run_end"] = 0;
          array[i]["start_time"] = 0;
        }
        k--;
        endtime = index;
        starttime = endtime;
        endtime = starttime + 7 * 24 * 3600000;
        if (endtime_set > 0 && endtime > endtime_set)
          endtime = endtime_set;
        spantime = endtime - starttime;
        first_time = 0;
        last_time = 0;
        week_begin = starttime;
      }
    }
    if (suc.length > 0 && suc[suc.length - 1].Time < endtime) {
      let run_time = 0;
      let week_total_time = 0;
      let device_count = 0;
      for (let i = 0; i < array.length; i++) {
        if (array[i]["run_start"] > 0)
          array[i]["run_time"] += (array[i]["run_end"] - array[i]["run_start"]);
        if (array[i]["run_time"] < 1000)
          continue;
        run_time += array[i]["run_time"];
        if (week_begin > 0 && (array[i]["start_time"] - week_begin) > g_nOffTime) {
          week_total_time += (array[i]["last_time"] - week_begin);
        }
        else {
          week_total_time += (array[i]["last_time"] - array[i]["start_time"]);
        }
        device_count++;
      }
      let run_time2 = run_time;
      starttime = first_time;
      spantime = week_total_time;
      if (spantime < run_time)
        spantime = run_time;
      date.setTime(starttime);
      let json = {};
      json["year"] = date.getFullYear();
      json["week"] = getYearWeek(starttime, 1);
      if (spantime < 1)
        json["oee"] = 0;
      else
        json["oee"] = parseInt(run_time * 100 / spantime + 0.5);
      console.log('周稼动率统计 OEE运行时间：' + run_time + '，总时长：' + spantime + ', OEE = ' + json["oee"]);
      let total_time = spantime;
      let total_time_15 = total_time;
      run_time = run_time2;
      dt.setTime(starttime);
      if (dt.getHours() >= 8) {
        setTime(dt, 8);
      }
      run_time2 = dt.getTime();
      endtime = parseInt(suc[suc.length - 1].Time);
      if (week_begin > 0)
        spantime = await CalcHolidayTime(week_begin, endtime);
      else
        spantime = await CalcHolidayTime(run_time2, endtime);
      let spantime_1 = spantime;
      spantime *= device_count;
      spantime += total_time_15;
      if (spantime < run_time)
        spantime = run_time;
      if (spantime < 1) // 防止run_time = 0
        spantime = 1;
      json["oee15"] = parseInt(run_time * 100 / spantime + 0.5);
      if (json["oee"] > 100)
        json["oee"] = 100;
      if (json["oee15"] > 100)
        json["oee15"] = 100;
      console.log('周稼动率统计 OEE1.5运行时间：' + run_time + '，总时长：' + spantime + ', OEE1.5 = ' + json["oee15"] + '，有效设备数目：' + device_count);
      temp.push(json);
      let week = getYearWeek(starttime);
      if (run_time > 0) {
        if (MachineName.length == 0) {
          sql = "select * from cncweek where week = '" + week + "'";
          let succ4 = await db_util.query(sql);
          if (succ4.length == 0)
            sql = "insert into cncweek (week, oee, oee15, run_time, total_time, total_time_15, last_time, last_id) values('" + week + "', '" + json["oee"] + "', '" + json["oee15"] + "', '" + run_time + "', '" + total_time + "', '" + spantime + "', '" + suc[suc.length - 1].Time + "', '" + suc[suc.length - 1].id + "')";
          else
            sql = "update cncweek set oee = '" + json["oee"] + "', oee15 = '" + json["oee15"] + "', run_time = '" + run_time + "', total_time = '" + total_time + "', total_time_15 = '" + spantime + "', last_time = '" + suc[suc.length - 1].Time + "', last_id = '" + suc[suc.length - 1].id + "' where week = '" + week + "'";
          await db_util.query(sql);
          succ4 = null;
        }
      }
      for (let i = 0; i < array.length; i++) {
        let name = MachineName;
        if (name.length == 0)
          name = g_cncInfo[i].MachineName;
        run_time = array[i]["run_time"];
        if (week_begin > 0 && (array[i]["start_time"] - week_begin) > g_nOffTime)
          total_time = (array[i]["last_time"] - week_begin);
        else
          total_time = (array[i]["last_time"] - array[i]["start_time"]);
        spantime = spantime_1 + total_time;
        if (total_time < 1000)
          total_time = 1000;
        if (spantime < 1000)
          spantime = run_time * 2;
        let oee = parseInt(run_time * 100 / total_time + 0.5);
        let oee15 = parseInt(run_time * 100 / spantime + 0.5);
        if (oee > 100)
          oee = 100;
        if (oee15 > 100)
          oee15 = 100;
        sql = "select * from cncweek where week = '" + week + "' and name = '" + name + "'";
        let succ4 = await db_util.query(sql);
        if (succ4.length == 0)
          sql = "insert into cncweek (week, name, oee, oee15, run_time, total_time, total_time_15, last_time, last_id) values('" + week + "', '" + name + "', '" + oee + "', '" + oee15 + "', '" + run_time + "', '" + total_time + "', '" + spantime + "', '" + array[i]["last_time"] + "', '" + array[i]["last_id"] + "')";
        else
          sql = "update cncweek set oee = '" + oee + "', oee15 = '" + oee15 + "', run_time = '" + run_time + "', total_time = '" + total_time + "', total_time_15 = '" + spantime + "', last_time = '" + array[i]["last_time"] + "', last_id = '" + array[i]["last_id"] + "' where week = '" + week + "' and name = '" + name + "'";
        await db_util.query(sql);
        succ4 = null;
      }
    }
    if (suc.length == 0 && temp.length == 0) {
      date.setTime(starttime);
      let json = {};
      json["year"] = date.getFullYear();
      json["week"] = getYearWeek(starttime, 1);
      json["oee"] = 0;
      json["oee15"] = 0;
      temp.push(json);
    }
    console.log(JSON.stringify(temp));
    cost_time = Date.now() - cost_time;
    if (suc.length > 0)
      console.log('StatisticOeeWeek cost time: ' + cost_time + 'ms, 最后一笔记录时间：' + suc[suc.length - 1].Time);
    else
      console.log('StatisticOeeWeek cost time: ' + cost_time + 'ms');
    suc = null;
    suc3 = null;
  }
  catch (error) {
    console.log('StatisticOeeWeek error: ' + error.message);
  }
  return temp;
}

async function ResetCncMonthData(date) {
  try {
    let month = getMonthDayTime(date);
    let sql = "delete from cncmonth where month = '" + month + "'";
    await db_util.query(sql);
    sql = "delete from currentmonth where month = '" + month + "'";
    await db_util.query(sql);
    console.log('删除表cncmonth和currentmonth中该月的数据', month);
  }
  catch (error) {
    console.log('ResetCncMonthData exception', error.message);
  }
}

async function CalcOeeAgain(body_MachineName, body_starttime, body_endtime) {
  let date = new Date();
  let cost_time = date.getTime();
  await ResetCncMonthData(date);
  await StatisticOeeMonth(body_MachineName, body_starttime, body_endtime);
  cost_time = Date.now() - cost_time;
  console.log('CalcOeeAgain end. cost time ' + cost_time);
}

async function StatisticOeeMonth(body_MachineName, body_starttime, body_endtime, onlyCalc) {
  let date = new Date();
  let cost_time = date.getTime();
  let array = new Array();
  let arrIndex = {};
  let MachineName = "";
  if (body_MachineName != undefined)
    MachineName = body_MachineName;
  for (let i = 0; i < g_cncInfo.length; i++) {
    if (MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName)
      continue;
    let json = {};
    json["start_time"] = 0; // 第一次记录的时间
    json["last_time"] = 0; // 上一次记录的时间，用于判断是否关机
    json["last_mode"] = "";
    json["last_id"] = 0;
    json["run_time"] = 0;
    json["run_start"] = 0;
    json["run_end"] = 0;
    json["run_time_old"] = 0;
    json["idle_time_old"] = 0;
    json["shutdown_time_old"] = 0;
    json["total_time_old"] = 0;
    json["total_time_15_old"] = 0;
    json["idle_time"] = 0;
    json["idle_start"] = 0;
    json["idle_end"] = 0;
    json["shutdown_time"] = 0;
    json["shutdown_start"] = 0;
    json["shutdown_end"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }

  let temp = new Array(); // 返回结果数组
  let flag = false;
  let run_time_old = 0;
  let idle_time_old = 0;
  let shutdown_time_old = 0;
  let total_time_old = 0;
  let starttime = Date.parse(body_starttime);
  let current_month = getMonthDayTime(date);
  let endtime_set = 0;
  if (body_endtime != undefined) {
    endtime_set = Date.parse(body_endtime);
    date.setTime(endtime_set);
    current_month = getMonthDayTime(date);
  }
  date.setTime(starttime);
  if (date.getHours() != 0) {
    console.log('StatisticOeeMonth starttime is ' + getMonthDayTime(date, 1, 1));
    setTime(date, 0);
    starttime = date.getTime();
  }
  let sql = getMonthDayTime(date);
  if (sql < current_month) {
    try {
      let firsttime = 0;
      let suc4 = await db_util.query("select value from cncother where name = 'firsttime'");
      if (suc4.length > 0) {
        firsttime = parseInt(suc4[0].value);
      }
      else {
        let suc3 = await db_util.query("select Time, fmtTime from cncdata ORDER BY Time ASC LIMIT 1");
        if (suc3.length > 0) {
          firsttime = parseInt(suc3[0].Time);
          let sql2 = "insert into cncother (name, value) values('firsttime', '" + suc3[0].Time + "')";
          await db_util.query(sql2);
        }
      }
      if (firsttime > 0) {
        let dt = new Date(firsttime);
        let month = getMonthDayTime(dt);
        let start_month = getMonthDayTime(date);
        while (start_month < month) {
          let json = {};
          json["year"] = date.getFullYear();
          json["month"] = date.getMonth() + 1;
          json["oee"] = 0;
          json["oee15"] = 0;
          temp.push(json);
          date.setMonth(date.getMonth() + 1);
          sql = getMonthDayTime(date);
          starttime = date.getTime();
          start_month = getMonthDayTime(date);
        }
        dt = null;
      }
      firsttime = date.getTime();
      while (sql < current_month) {
        let json = {};
        json["year"] = date.getFullYear();
        json["month"] = date.getMonth() + 1;
        json["oee"] = 0;
        json["oee15"] = 0;
        temp.push(json);
        date.setMonth(json['month']);
        sql = getMonthDayTime(date);
      }
      date.setTime(firsttime);
      sql = getMonthDayTime(date);
      let suc2 = await db_util.query("select * from cncmonth where name = '" + MachineName + "'");
      for (let i = 0; i < suc2.length; i++) {
        if (suc2[i].month < sql)
          continue;
        else if (suc2[i].month > current_month)
          break;
        if (suc2[i].month < current_month) {
          let month = parseInt(suc2[i]['month'].substr(5));
          for (let k = 0; k < temp.length; k++) {
            if (temp[k]['month'] == month) {
              temp[k]['oee'] = parseFloat(suc2[i].oee);
              temp[k]['oee15'] = parseFloat(suc2[i].oee15);
              break;
            }
          }
          date.setMonth(date.getMonth() + 1);
          sql = getMonthDayTime(date);
          starttime = date.getTime();
        }
        else {
          run_time_old = parseInt(suc2[i].run_time);
          idle_time_old = parseInt(suc2[i].idle_time);
          shutdown_time_old = parseInt(suc2[i].shutdown_time);
          total_time_old = parseInt(suc2[i].total_time);
          let last_time = parseInt(suc2[i].last_time);
          if (last_time > 0)
            starttime = last_time;
        }
      }
      if (MachineName.length == 0) {
        sql = "select * from cncmonth where month = '" + current_month + "' and length(name) > 0";
        let suc4 = await db_util.query(sql);
        for (let i = 0; i < suc4.length; i++) {
          let index = arrIndex[suc4[i].name];
          if (isNaN(index))
            continue;
          array[index]["run_time_old"] = parseInt(suc4[i].run_time);
          array[index]["idle_time_old"] = parseInt(suc4[i].idle_time);
          array[index]["shutdown_time_old"] = parseInt(suc4[i].shutdown_time);
          array[index]["total_time_old"] = parseInt(suc4[i].total_time);
          array[index]["total_time_15_old"] = parseInt(suc4[i].total_time_15);
          array[index]["last_time"] = parseInt(suc4[i].last_time);
          array[index]["last_mode"] = suc4[i].last_mode;
          array[index]["last_id"] = parseInt(suc4[i].last_id);
          array[index]["start_time"] = array[index]["last_time"];
          if (array[index]["last_mode"] == "Run")
            array[index]["run_start"] = array[index]["last_time"];
        }
      }
      suc2 = null;
    }
    catch (err) {
      console.log('query cncmonth error: ' + err.message);
    }
  }
  date.setTime(cost_time);
  sql = getMonthDayTime(date, 1, 1);
  date.setTime(starttime);
  //console.log('StatisticOeeMonth on ' + sql + ', ' + body_starttime + ' from ' + starttime + ' [' + getMonthDayTime(date, 1, 1) + ']');

  sql = "select id, MachineName, Time, Operation_Mode from cncdata";
  if (flag) {
    sql += " and Time >= '" + starttime + "'";
  }
  else {
    flag = true;
    sql += " where Time >= '" + starttime + "'";
  }
  if (endtime_set > 0) {
    if (flag) {
      sql += " and Time < '" + endtime_set + "'";
    }
    else {
      flag = true;
      sql += " where Time < '" + endtime_set + "'";
    }
  }
  if (MachineName.length > 0) {
    if (flag) {
      sql += " and MachineName = '" + MachineName + "'";
    }
    else {
      flag = true;
      sql += " where MachineName = '" + MachineName + "'";
    }
  }
  sql += " ORDER BY Time ASC";
  //console.log(sql);
  try {
    let suc = await db_util.query(sql);

    date.setTime(starttime);
    date.setMonth(date.getMonth() + 1);
    let dt = new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0);
    let endtime = dt.getTime();
    if (endtime_set > 0 && endtime > endtime_set)
      endtime = endtime_set;
    let spantime = endtime - starttime;

    let index = suc.length;
    let currentTime = 0;
    let first_time = 0; // 月份的第一个数据，和最后一个数据一起统计spantime
    let last_time = 0;
    for (let k = 0; k < suc.length; k++) {
      index = arrIndex[suc[k].MachineName];
      if (isNaN(index) || index < 0 || index >= array.length)
        continue;
      currentTime = parseInt(suc[k].Time);
      if (currentTime < endtime) {
        if (first_time == 0)
          first_time = currentTime;
        last_time = currentTime;
        array[index]["last_id"] = suc[k].id;
        if (array[index]["start_time"] == 0)
          array[index]["start_time"] = currentTime;
        // 判断是否有关机过程
        if (array[index]["last_time"] > 0 && (currentTime - array[index]["last_time"]) > g_nOffTime) // 间隔时间大于10分钟
        {
          //console.log(suc[k].MachineName + '关机，从' + array[index]["last_time"] + '到' + currentTime + ', 时长：' + parseInt((currentTime - array[index]["last_time"])));
          if (array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0) {
            array[index]["run_time"] += (array[index]["last_time"] - array[index]["run_start"]);
          }
          if (array[index]["last_mode"] == "Idle" && array[index]["idle_start"] > 0) {
            array[index]["idle_time"] += (array[index]["last_time"] - array[index]["idle_start"]);
          }
          if (array[index]["last_mode"] == "Shutdown" && array[index]["shutdown_start"] > 0) {
            array[index]["shutdown_time"] += (array[index]["last_time"] - array[index]["shutdown_start"]);
          }
          array[index]["run_start"] = 0;
          array[index]["idle_start"] = 0;
          array[index]["shutdown_start"] = 0;
        }
        array[index]["last_time"] = currentTime;
        array[index]["last_mode"] = suc[k].Operation_Mode;

        // 计算运行时间
        array[index]["run_end"] = currentTime;
        if (suc[k].Operation_Mode == "Run") {
          if (array[index]["run_start"] == 0)
            array[index]["run_start"] = currentTime;
        }
        else if (array[index]["run_start"] > 0) {
          array[index]["run_time"] += (currentTime - array[index]["run_start"]);
          array[index]["run_start"] = 0;
          array[index]["run_end"] = 0;
        }

        // 计算等待时间
        array[index]["idle_end"] = currentTime;
        if (suc[k].Operation_Mode == "Idle") {
          if (array[index]["idle_start"] == 0)
            array[index]["idle_start"] = currentTime;
        }
        else if (array[index]["idle_start"] > 0) {
          array[index]["idle_time"] += (currentTime - array[index]["idle_start"]);
          array[index]["idle_start"] = 0;
          array[index]["idle_end"] = 0;
        }

        // 计算故障时间
        array[index]["shutdown_end"] = currentTime;
        if (suc[k].Operation_Mode == "Shutdown") {
          if (array[index]["shutdown_start"] == 0)
            array[index]["shutdown_start"] = currentTime;
        }
        else if (array[index]["shutdown_start"] > 0) {
          array[index]["shutdown_time"] += (currentTime - array[index]["shutdown_start"]);
          array[index]["shutdown_start"] = 0;
          array[index]["shutdown_end"] = 0;
        }
      }
      else // 到了下一个月份了
      {
        sql = "当前月份结束：";
        sql += getMonthDayTime2(endtime, 1, 1, 1);
        sql += "，新时间：";
        sql += getMonthDayTime2(currentTime, 1, 1, 1);
        sql += "，数据序号：";
        sql += k.toString();
        console.log(sql);
        let run_time = 0;
        let idle_time = 0;
        let shutdown_time = 0;
        let off_time = 0;
        let total_time = 0;
        let device_count = 0;
        for (let i = 0; i < array.length; i++) {
          if (array[i]["run_start"] > 0 && array[i]["run_end"] > array[i]["run_start"])
            array[i]["run_time"] += (array[i]["run_end"] - array[i]["run_start"]);
          if (array[i]["idle_start"] > 0 && array[i]["idle_end"] > array[i]["idle_start"])
            array[i]["idle_time"] += (array[i]["idle_end"] - array[i]["idle_start"]);
          if (array[i]["shutdown_start"] > 0 && array[i]["shutdown_end"] > array[i]["shutdown_start"])
            array[i]["shutdown_time"] += (array[i]["shutdown_end"] - array[i]["shutdown_start"]);

          off_time = array[i]["run_time"] + array[i]["idle_time"] + array[i]["shutdown_time"];
          off_time += (array[i]["run_time_old"] + array[i]["idle_time_old"] + array[i]["shutdown_time_old"]);
          if (off_time < 1000)
            continue;
          device_count++;

          run_time += array[i]["run_time"];
          idle_time += array[i]["idle_time"];
          shutdown_time += array[i]["shutdown_time"];
          if (array[i]["start_time"] > 0 && array[i]["last_time"] > array[i]["start_time"])
            total_time += (array[i]["last_time"] - array[i]["start_time"]);
        }
        off_time = total_time - run_time - idle_time - shutdown_time;
        if (off_time < 0)
          off_time = 0;
        let run_time2 = run_time;
        if (run_time > total_time)
          total_time = run_time;
        if (total_time < 1)
          total_time = 1;
        spantime = total_time;
        dt.setTime(starttime);
        let json = {};
        json["year"] = dt.getFullYear();
        json["month"] = dt.getMonth() + 1;
        json["oee"] = parseInt(run_time * 100 / total_time + 0.5);
        //console.log(json["year"] + '-' + json["month"] + ' oee = ' + json["oee"]);
        //console.log('OEE运行时间：' + run_time + '，总时长：' + total_time + ', OEE = ' + json["oee"]);
        run_time = run_time2;
        run_time2 = first_time; //starttime;
        index = endtime;
        endtime = last_time;
        spantime = await CalcHolidayTime(first_time, last_time, null, 1);
        let spantime_1 = spantime;
        spantime *= device_count;
        spantime += total_time;
        if (spantime < 1000) {
          spantime = run_time;
          if (spantime == 0)
            spantime = 1;
        }
        if (run_time > spantime)
          spantime = run_time;
        json["oee15"] = parseInt(run_time * 100 / spantime + 0.5);
        if (isNaN(json["oee15"]))
          json["oee15"] = 0;
        if (device_count < 5)
          console.log('StatisticOeeMonth OEE1.5运行时间：' + run_time + '，总时长：' + spantime + ', OEE1.5 = ' + json["oee15"] + '，有效设备数目：' + device_count);
        temp.push(json);
        if (onlyCalc == undefined) {
          month = getMonthDayTime(dt);
          if (MachineName.length == 0) {
            sql = "select * from cncmonth where month = '" + month + "' and name = ''";
            let succ4 = await db_util.query(sql);
            let m = 0;
            if (k > 0)
              m = k - 1;
            if (succ4.length == 0)
              sql = "insert into cncmonth values('" + month + "', '', '" + json["oee"] + "', '" + json["oee15"] + "', '" + run_time + "', '" + total_time + "', '" + spantime + "', '" + suc[m].Time + "', '" + suc[m].id + "', '', '" + idle_time + "', '" + shutdown_time + "', '" + off_time + "')";
            else
              sql = "update cncmonth set oee = '" + json["oee"] + "', oee15 = '" + json["oee15"] + "', run_time = '" + run_time + "', total_time = '" + total_time + "', total_time_15 = '" + spantime + "', last_time = '" + suc[m].Time + "', last_id = '" + suc[m].id + "', idle_time = '" + idle_time + "', shutdown_time = '" + shutdown_time + "', off_time = '" + off_time + "' where month = '" + month + "' and name = ''";
            await db_util.query(sql);
            succ4 = null;
          }
          for (let i = 0; i < array.length; i++) {
            let name = MachineName;
            if (name.length == 0)
              name = g_cncInfo[i].MachineName;
            run_time = array[i]["run_time"];
            idle_time = array[i]["idle_time"];
            shutdown_time = array[i]["shutdown_time"];
            total_time = (array[i]["last_time"] - array[i]["start_time"]);
            off_time = total_time - run_time - idle_time - shutdown_time;
            if (off_time < 0)
              off_time = 0;
            spantime = spantime_1 + total_time;
            if (total_time < 1)
              total_time = 1;
            if (spantime < 1) {
              spantime = run_time;
              if (spantime < 1)
                spantime = 1;
            }
            if (run_time > total_time)
              total_time = run_time;
            if (run_time > spantime)
              spantime = run_time;
            let oee = parseInt(run_time * 100 / total_time + 0.5);
            let oee15 = parseInt(run_time * 100 / spantime + 0.5);
            if (isNaN(oee))
              oee = 0;
            if (isNaN(oee15))
              oee15 = 0;
            sql = "select * from cncmonth where month = '" + month + "' and name = '" + name + "'";
            let succ4 = await db_util.query(sql);
            if (succ4.length == 0)
              sql = "insert into cncmonth values('" + month + "', '" + name + "', '" + oee + "', '" + oee15 + "', '" + run_time + "', '" + total_time + "', '" + spantime + "', '" + array[i]["last_time"] + "', '" + array[i]["last_id"] + "', '" + array[i]["last_mode"] + "', '" + idle_time + "', '" + shutdown_time + "', '" + off_time + "')";
            else
              sql = "update cncmonth set oee = '" + oee + "', oee15 = '" + oee15 + "', run_time = '" + run_time + "', total_time = '" + total_time + "', total_time_15 = '" + spantime + "', last_time = '" + array[i]["last_time"] + "', last_id = '" + array[i]["last_id"] + "', last_mode = '" + array[i]["last_mode"] + "', idle_time = '" + idle_time + "', shutdown_time = '" + shutdown_time + "', off_time = '" + off_time + "' where month = '" + month + "' and name = '" + name + "'";
            await db_util.query(sql);
            succ4 = null;
          }
        }
        for (let i = 0; i < array.length; i++) {
          array[i]["start_time"] = 0;
          array[i]["run_time"] = 0;
          array[i]["run_start"] = 0;
          array[i]["run_end"] = 0;
          array[i]["idle_time"] = 0;
          array[i]["idle_start"] = 0;
          array[i]["idle_end"] = 0;
          array[i]["shutdown_time"] = 0;
          array[i]["shutdown_start"] = 0;
          array[i]["shutdown_end"] = 0;
        }

        k--;
        endtime = index;
        dt.setTime(endtime);
        dt.setMonth(dt.getMonth() + 1);
        dt.setDate(1);
        starttime = endtime;
        endtime = dt.getTime();
        if (endtime_set > 0 && endtime > endtime_set)
          endtime = endtime_set;
        spantime = endtime - starttime;
        first_time = 0;
        last_time = 0;
        console.log('下一个月份：' + getMonthDayTime(dt), getMonthDayTime2(starttime, 1), getMonthDayTime2(endtime, 1));
      }
    }
    if (suc.length > 0 && suc[suc.length - 1].Time < endtime) {
      let run_time = run_time_old;
      let idle_time = idle_time_old;
      let shutdown_time = shutdown_time_old;
      let off_time = 0;
      let month_total_time = total_time_old;
      let device_count = 0;
      for (let i = 0; i < array.length; i++) {
        if (array[i]["run_start"] > 0 && array[i]["run_end"] > array[i]["run_start"])
          array[i]["run_time"] += (array[i]["run_end"] - array[i]["run_start"]);
        if (array[i]["idle_start"] > 0 && array[i]["idle_end"] > array[i]["idle_start"])
          array[i]["idle_time"] += (array[i]["idle_end"] - array[i]["idle_start"]);
        if (array[i]["shutdown_start"] > 0 && array[i]["shutdown_end"] > array[i]["shutdown_start"])
          array[i]["shutdown_time"] += (array[i]["shutdown_end"] - array[i]["shutdown_start"]);

        off_time = array[i]["run_time"] + array[i]["idle_time"] + array[i]["shutdown_time"];
        off_time += (array[i]["run_time_old"] + array[i]["idle_time_old"] + array[i]["shutdown_time_old"]);
        if (off_time < 1000)
          continue;
        device_count++;

        run_time += array[i]["run_time"];
        idle_time += array[i]["idle_time"];
        shutdown_time += array[i]["shutdown_time"];
        if (array[i]["start_time"] > 0 && array[i]["last_time"] > array[i]["start_time"])
          month_total_time += (array[i]["last_time"] - array[i]["start_time"]);
        //else if( MachineName.length == 0 )
        //  console.log('提示: ' + g_cncInfo[i].MachineName + ' 结束时间小于开始时间 ' + array[i]["last_time"] + ' <= ' + array[i]["start_time"]);
      }
      let run_time2 = run_time;
      starttime = first_time;
      spantime = month_total_time;
      if (spantime < 1000)
        spantime = 1000;
      if (run_time > spantime)
        spantime = run_time;
      dt.setTime(starttime);
      month = getMonthDayTime(dt);
      let json = {};
      json["year"] = dt.getFullYear();
      json["month"] = dt.getMonth() + 1;
      json["oee"] = parseInt(run_time * 100 / spantime + 0.5);
      if (device_count < 5)
        console.log('StatisticOeeMonth OEE运行时间：' + run_time + '，总时长：' + spantime + ', OEE = ' + run_time * 100 / spantime + '，有效设备数目：' + device_count);
      let total_time = spantime;
      off_time = total_time - run_time - idle_time - shutdown_time;
      if (off_time < 0)
        off_time = 0;
      let total_time_15 = total_time;
      run_time = run_time2;
      /*dt.setTime(starttime);
      if( dt.getHours() >= 8 )
      {
        setTime(dt, 8);
      }*/
      currentTime = parseInt(suc[suc.length - 1].Time);
      dt.setTime(currentTime); // 必须计算本月所有的休息时间
      dt.setDate(1);
      setTime(dt, 0);
      run_time2 = dt.getTime();
      endtime = currentTime;//parseInt(suc[suc.length-1].Time);
      starttime = run_time2;
      spantime = await CalcHolidayTime(run_time2, endtime, null, 1);
      let spantime_1 = spantime;
      spantime *= device_count;
      //console.log('oee15 spantime: ' + spantime_1/3600000 + '小时/台，' + device_count);
      spantime += total_time_15;
      if (spantime < run_time) {
        console.log('月稼动率统计 OEE1.5运行时间：' + run_time + '，总时长：' + spantime + ', OEE1.5 = ' + dotFixed(run_time * 100 / spantime) + '%');
        spantime = run_time;
      }
      json["oee15"] = parseInt(run_time * 100 / spantime + 0.5);
      temp.push(json);
      if (json["oee15"] > 100) {
        console.log('月稼动率统计 OEE1.5计算异常？' + json["oee15"]);
        setTimeout(function () { CalcOeeAgain(body_MachineName, body_starttime, body_endtime); }, 1000);
      }
      if (onlyCalc == undefined) {
        let flag = false;
        sql = "select * from currentmonth where month = '" + month + "' and MachineName != 'total'";
        let suc5 = await db_util.query(sql);
        for (let i = 0; i < suc5.length; i++) {
          if (suc5[i]['last_mode'] != 'OFF')
            continue;
          for (let k = 0; k < array.length; k++) {
            let name = MachineName;
            if (name.length == 0)
              name = g_cncInfo[k].MachineName;
            if (suc5[i]['MachineName'] == name) {
              if (array[k]['last_mode'] != 'OFF') {
                console.log(name + ' 开机了');
                flag = true;
              }
              break;
            }
          }
          if (flag)
            break;
        }
        if (flag) {
          console.log('有设备开机，需要重新计算本月数据');
          await ResetCncMonthData(date);
        }
      }
      if (MachineName.length == 0 && onlyCalc == undefined) {
        sql = "select * from cncmonth where month = '" + month + "' and length(name) = 0";
        let succ4 = await db_util.query(sql);
        if (succ4.length == 0)
          sql = "insert into cncmonth values('" + month + "', '', '" + json["oee"] + "', '" + json["oee15"] + "', '" + run_time + "', '" + total_time + "', '" + spantime + "', '" + suc[suc.length - 1].Time + "', '" + suc[suc.length - 1].id + "', '', '" + idle_time + "', '" + shutdown_time + "', '" + off_time + "')";
        else
          sql = "update cncmonth set oee = '" + json["oee"] + "', oee15 = '" + json["oee15"] + "', run_time = '" + run_time + "', total_time = '" + total_time + "', total_time_15 = '" + spantime + "', last_time = '" + suc[suc.length - 1].Time + "', last_id = '" + suc[suc.length - 1].id + "', idle_time = '" + idle_time + "', shutdown_time = '" + shutdown_time + "', off_time = '" + off_time + "' where month = '" + month + "' and length(name) = 0";
        await db_util.query(sql);
        succ4 = null;
        sql = "select * from currentmonth where month = '" + month + "' and MachineName = 'total'";
        let suc5 = await db_util.query(sql);
        if (suc5.length > 0) {
          sql = "update currentmonth set run_time = '" + run_time + "', idle_time = '" + idle_time + "', ";
          sql += "shutdown_time = '" + shutdown_time + "', off_time = '" + off_time + "', ";
          sql += "total_time = '" + total_time + "', last_time = '" + suc[suc.length - 1].Time + "', ";
          sql += "last_id = '" + suc[suc.length - 1].id + "', ";
          sql += "last_mode = '" + suc[suc.length - 1].Operation_Mode + "' ";
          sql += "where month = '" + month + "' and MachineName = 'total'";
        }
        else {
          sql = "insert into currentmonth (month, MachineName, run_time, idle_time, shutdown_time, off_time, total_time, last_time, last_id, last_mode) ";
          sql += "values ('" + month + "', 'total', '" + run_time + "', ";
          sql += "'" + idle_time + "', '" + shutdown_time + "', '" + off_time + "', '" + total_time + "', "
          sql += "'" + suc[suc.length - 1].Time + "', '" + suc[suc.length - 1].id + "', '" + suc[suc.length - 1].Operation_Mode + "')";
        }
        await db_util.query(sql);
        suc5 = null;
      }
      for (let i = 0; i < array.length; i++) {
        if (array[i]["start_time"] == 0 || array[i]["last_time"] <= array[i]["start_time"]) {
          continue;
        }
        let name = MachineName;
        if (name.length == 0)
          name = g_cncInfo[i].MachineName;
        run_time = array[i]["run_time"] + array[i]["run_time_old"];
        idle_time = array[i]["idle_time"] + array[i]["idle_time_old"];
        shutdown_time = array[i]["shutdown_time"] + array[i]["shutdown_time_old"];
        total_time = (array[i]["last_time"] - array[i]["start_time"]);
        spantime = spantime_1 + total_time;
        total_time += array[i]["total_time_old"];
        spantime += array[i]["total_time_old"];
        off_time = total_time - run_time - idle_time - shutdown_time;
        if (off_time < 0)
          off_time = 0;
        if (total_time < run_time)
          total_time = run_time;
        if (spantime < run_time)
          spantime = run_time;
        let oee = parseInt(run_time * 100 / total_time + 0.5);
        let oee15 = parseInt(run_time * 100 / spantime + 0.5);
        if (onlyCalc == undefined) {
          sql = "select * from cncmonth where month = '" + month + "' and name = '" + name + "'";
          let succ4 = await db_util.query(sql);
          if (succ4.length == 0)
            sql = "insert into cncmonth values('" + month + "', '" + name + "', '" + oee + "', '" + oee15 + "', '" + run_time + "', '" + total_time + "', '" + spantime + "', '" + array[i]["last_time"] + "', '" + array[i]["last_id"] + "', '" + array[i]["last_mode"] + "', '" + idle_time + "', '" + shutdown_time + "', '" + off_time + "')";
          else
            sql = "update cncmonth set oee = '" + oee + "', oee15 = '" + oee15 + "', run_time = '" + run_time + "', total_time = '" + total_time + "', total_time_15 = '" + spantime + "', last_time = '" + array[i]["last_time"] + "', last_id = '" + array[i]["last_id"] + "', last_mode = '" + array[i]["last_mode"] + "', idle_time = '" + idle_time + "', shutdown_time = '" + shutdown_time + "', off_time = '" + off_time + "' where month = '" + month + "' and name = '" + name + "'";
          await db_util.query(sql);
          succ4 = null;
          sql = "select * from currentmonth where month = '" + month + "' and MachineName = '" + name + "'";
          let suc5 = await db_util.query(sql);
          if (suc5.length > 0) {
            sql = "update currentmonth set run_time = '" + run_time + "', idle_time = '" + idle_time + "', ";
            sql += "shutdown_time = '" + shutdown_time + "', off_time = '" + off_time + "', ";
            sql += "total_time = '" + total_time + "', last_time = '" + array[i]["last_time"] + "', ";
            sql += "last_id = '" + array[i]["last_id"] + "', ";
            sql += "last_mode = '" + array[i]["last_mode"] + "' ";
            sql += "where month = '" + month + "' and MachineName = '" + name + "'";
          }
          else {
            sql = "insert into currentmonth (month, MachineName, run_time, idle_time, shutdown_time, off_time, total_time, last_time, last_id, last_mode) ";
            sql += "values ('" + month + "', '" + name + "', '" + run_time + "', ";
            sql += "'" + idle_time + "', '" + shutdown_time + "', '" + off_time + "', '" + total_time + "', "
            sql += "'" + array[i]["last_time"] + "', '" + array[i]["last_id"] + "', '" + array[i]["last_mode"] + "')";
          }
          await db_util.query(sql);
          suc5 = null;
        }
      }
    }
    if (suc.length == 0 && temp.length == 0) {
      dt.setTime(starttime);
      let json = {};
      json["year"] = dt.getFullYear();
      json["month"] = dt.getMonth() + 1;
      json["oee"] = 0;
      json["oee15"] = 0;
      temp.push(json);
    }

    cost_time = Date.now() - cost_time;
    /*if( suc.length > 0 )
      console.log('StatisticOeeMonth cost time: ' + cost_time + 'ms, 最新记录时间：' + suc[suc.length-1].Time + '，最新ID：' + suc[suc.length-1].id);
    else
      console.log('StatisticOeeMonth cost time: ' + cost_time + 'ms');*/
    suc = null;
    suc3 = null;
  }
  catch (error) {
    console.log('StatisticOeeMonth error', error.message, sql);
  }
  return temp;
}

//NOUSE
app.post('/QueryCncOeeMonth', async (req, res) => {
  if (req.body.starttime == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set starttime parameter" })
    return;
  }
  else {
    if (req.body.starttime < "2019-06-01 08:00:00") {
      //console.log('QueryCncOeeMonth starttime error: ' + req.body.starttime + ' from ' + req.ip);
      res.status(404);
      res.end();
      return;
    }
  }
  if (g_cncOeeMonthBusy) {
    console.log('QueryCncOeeMonth: the service is busy now');
    res.status(200);
    res.json({ "result": "error", "description": "the service is busy now" })
    return;
  }
  g_cncOeeMonthBusy = true;

  let temp = await StatisticOeeMonth(req.body.MachineName, req.body.starttime, req.body.endtime);

  g_cncOeeMonthBusy = false;
  res.status(200);
  res.json({ "result": "ok", "oee": temp });
})

//NOUSE
app.post('/QueryCncOeeWeek', async (req, res) => {
  if (req.body.starttime == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set starttime parameter" })
    return;
  }
  else {
    if (req.body.starttime < "2019-06-01 08:00:00") {
      //console.log('QueryCncOeeMonth starttime error: ' + req.body.starttime + ' from ' + req.ip);
      res.status(404);
      res.end();
      return;
    }
  }
  if (g_cncOeeMonthBusy) {
    console.log('QueryCncOeeWeek: the service is busy now');
    res.status(200);
    res.json({ "result": "error", "description": "the service is busy now" })
    return;
  }
  g_cncOeeMonthBusy = true;

  let temp = await StatisticOeeWeek(req.body.MachineName, req.body.starttime, req.body.endtime);

  g_cncOeeMonthBusy = false;
  res.status(200);
  res.json({ "result": "ok", "oee": temp });
})

function CalcBanciTime(currentTime, run_start) {
  let json = {};
  json["run_time"] = 0;
  json["run_time_ye"] = 0;
  if (run_start < 1590940800000) // 2020-06-01 00:00:00
  {
    console.log('run_start is null');
    return json;
  }
  let dt = new Date(currentTime);
  let dt2 = new Date(run_start);
  if (currentTime <= run_start) // 二者的时间差应该不超过24小时
  {
    console.log('CalcBanciTime 当前时间：' + getMonthDayTime(dt, 1, 1) + ', 开始时间：' + getMonthDayTime(dt2, 1, 1));
    return json;
  }
  let hour = dt.getHours();
  let start_hour = dt2.getHours();
  if (start_hour < 8) {
    if (hour < start_hour) // 到第二天了
    {
      setTime(dt2, 8);
      json["run_time_ye"] = dt2.getTime() - run_start;
      json["run_time"] = 12 * 3600 * 1000;
      setTime(dt2, 20);
      json["run_time_ye"] += (currentTime - dt2.getTime());
    }
    else if (hour < 8) {
      json["run_time_ye"] = currentTime - run_start;
      json["run_time"] = 0;
    }
    else if (hour < 20) {
      setTime(dt, 8);
      json["run_time_ye"] = dt.getTime() - run_start;
      json["run_time"] = currentTime - dt.getTime();
    }
    else {
      json["run_time"] = 12 * 3600 * 1000;
      json["run_time_ye"] = currentTime - run_start - json["run_time"];
    }
  }
  else if (start_hour < 20) // 8 <= start_hour < 20
  {
    if (hour < 8) {
      setTime(dt, 20);
      json["run_time"] = dt.getTime() - run_start;
      json["run_time_ye"] = currentTime - dt.getTime();
    }
    else if (hour < 20) {
      if (hour < start_hour) // 到第二天了
      {
        setTime(dt2, 20);
        json["run_time"] = dt2.getTime() - run_start;
        json["run_time_ye"] = currentTime - dt2.getTime();
      }
      else {
        json["run_time"] = currentTime - run_start;
        json["run_time_ye"] = 0;
      }
    }
    else {
      setTime(dt, 20);
      json["run_time"] = dt.getTime() - run_start;
      json["run_time_ye"] = currentTime - dt.getTime();
    }
  }
  else // start_hour >= 20
  {
    if (hour < 8) {
      json["run_time"] = 0;
      json["run_time_ye"] = currentTime - run_start;
    }
    else if (hour < 20) {
      setTime(dt, 8);
      json["run_time"] = currentTime - dt.getTime();
      json["run_time_ye"] = dt.getTime() - run_start;
    }
    else {
      if (hour < start_hour) // 到第二天了
      {
        json["run_time"] = 12 * 3600 * 1000;
        json["run_time_ye"] = currentTime - run_start - json["run_time"];
      }
      else {
        json["run_time"] = 0;
        json["run_time_ye"] = currentTime - run_start;
      }
    }
  }
  return json;
}

//NOUSE 以下只计算指定月份中白班/夜班的OEE和OEE1.5
app.post('/QueryCncOeeMonthEx', async (req, res) => {
  if (req.body.starttime == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set starttime parameter" })
    return;
  }
  //let date = new Date();
  let array = new Array();
  let arrIndex = {};
  let MachineName = "";
  if (req.body.MachineName != undefined)
    MachineName = req.body.MachineName;
  for (let i = 0; i < g_cncInfo.length; i++) {
    if (MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName)
      continue;
    let json = {};
    json["last_time"] = 0; // 上一次记录的时间，用于判断是否关机
    json["last_mode"] = "";
    json["last_hour"] = 100;
    json["run_time"] = 0; // 白班时间
    json["run_time_ye"] = 0; // 夜班时间
    json["run_total"] = 0;
    json["run_start"] = 0;
    json["run_end"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }

  let starttime = Date.parse(req.body.starttime);
  let dt = new Date(starttime);
  let sql = 'QueryCncOeeMonthEx: ' + getMonthDayTime(dt, 1, 1);
  let month = dt.getMonth();
  dt.setMonth(month + 1);
  let dt2 = new Date(dt.getFullYear(), dt.getMonth(), 1, 0, 0, 0);
  let endtime = dt2.getTime();
  sql += (' ~ ' + getMonthDayTime(dt2, 1, 1));
  console.log(sql);

  sql = "select MachineName, Time, Operation_Mode from cncdata where Time >= '" + starttime + "'";
  if (MachineName.length > 0)
    sql += " and MachineName = '" + MachineName + "'";
  sql += " ORDER BY Time ASC";
  //console.log(sql);
  try {
    let suc3 = await db_util.query("select * from cnctime");
    let suc = await db_util.query(sql);
    let currentTime = 0;
    if (suc.length > 0) {
      if (starttime < suc[0].Time)
        starttime = parseInt(suc[0].Time);
      while (endtime <= starttime) {
        month = dt2.getMonth();
        dt2.setMonth(month + 1);
        endtime = dt2.getTime();
      }
      currentTime = parseInt(suc[suc.length - 1].Time);
      if (currentTime < endtime)
        endtime = currentTime;
    }
    let spantime = 0;
    let spantime_ye = 0;
    let index = 0;
    currentTime = starttime;
    month = 12 * 3600 * 1000;
    dt.setTime(currentTime);
    dt2.setTime(currentTime);
    setTime(dt2, 8);
    let st = dt2.getTime();
    let et = st + month;
    if (endtime <= (et + month / 3)) {
      if (currentTime <= st) {
        spantime_ye += (st - currentTime);
        if (endtime <= et) {
          spantime += (endtime - st);
        }
        else {
          spantime += month;
          spantime_ye += (endtime - et);
        }
      }
      else if (currentTime <= et) {
        if (endtime <= et) {
          spantime += (endtime - currentTime);
        }
        else {
          spantime += (et - currentTime);
          spantime_ye += (endtime - et);
        }
      }
      else {
        spantime_ye += (endtime - currentTime);
      }
    }
    else {
      if (currentTime <= st) {
        spantime_ye += (st - currentTime);
        spantime += month;
        spantime_ye += month / 3;
      }
      else if (currentTime <= et) {
        spantime += (et - currentTime);
        spantime_ye += month / 3;
      }
      else {
        spantime_ye += (et + month / 3 - currentTime);
      }
      currentTime = et + month / 3;
      while ((currentTime + month * 2) <= endtime) {
        spantime += month;
        spantime_ye += month;
        currentTime += month * 2;
      }
      st = currentTime + month * 2 / 3;
      et = st + month;
      if (endtime <= st) {
        spantime_ye += (endtime - currentTime);
      }
      else if (endtime <= et) {
        spantime_ye += month * 2 / 3;
        spantime += (endtime - st);
      }
      else {
        spantime_ye += month * 2 / 3;
        spantime += month;
        spantime_ye += (endtime - et);
      }
    }
    let temp = new Array();
    for (let k = 0; k < suc.length; k++) {
      index = arrIndex[suc[k].MachineName];
      if (isNaN(index))
        continue;
      currentTime = parseInt(suc[k].Time);
      dt.setTime(currentTime);
      let hour = dt.getHours();
      // 判断是否有关机过程
      if (array[index]["last_time"] > 0 && (currentTime - array[index]["last_time"]) > g_nOffTime) // 间隔时间大于10分钟
      {
        if (array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0) {
          let ret = CalcBanciTime(array[index]["last_time"], array[index]["run_start"]);
          array[index]["run_time"] += ret.run_time;
          array[index]["run_time_ye"] += ret.run_time_ye;
        }
        array[index]["run_start"] = 0;
      }
      else if (array[index]["last_hour"] < 24 && hour != array[index]["last_hour"]) {
        if (array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0) {
          if ((array[index]["last_hour"] == 7 && hour == 8) || (array[index]["last_hour"] == 19 && hour == 20)) {
            let ret = CalcBanciTime(currentTime, array[index]["run_start"]);
            array[index]["run_time"] += ret.run_time;
            array[index]["run_time_ye"] += ret.run_time_ye;
            array[index]["run_start"] = 0;
            //if( index == 0 )
            //  console.log(getMonthDayTime(dt, 1, 1) + ' - 2 白班/夜班时间: ' + ret.run_time + '/' + ret.run_time_ye);
          }
        }
      }
      array[index]["last_hour"] = hour;
      array[index]["last_time"] = currentTime;
      array[index]["last_mode"] = suc[k].Operation_Mode;

      // 计算运行时间
      array[index]["run_end"] = currentTime;
      if (suc[k].Operation_Mode == "Run") {
        if (array[index]["run_start"] == 0)
          array[index]["run_start"] = currentTime;
      }
      else if (array[index]["run_start"] > 0) {
        let ret = CalcBanciTime(currentTime, array[index]["run_start"]);
        array[index]["run_time"] += ret.run_time;
        array[index]["run_time_ye"] += ret.run_time_ye;
        array[index]["run_start"] = 0;
        array[index]["run_end"] = 0;
      }
      if (k == suc.length - 1) {
        for (let i = 0; i < array.length; i++) {
          if (array[i]["run_start"] > 0) {
            let ret = CalcBanciTime(array[i]["run_end"], array[i]["run_start"]);
            array[index]["run_time"] += ret.run_time;
            array[index]["run_time_ye"] += ret.run_time_ye;
          }
        }
      }
    }
    if (suc.length > 0) {
      let run_time = 0;
      let run_time_ye = 0;
      let device_count = 0;
      let device_count_ye = 0;
      for (let i = 0; i < array.length; i++) {
        run_time += array[i]["run_time"];
        run_time_ye += array[i]["run_time_ye"];
        if (array[i]["run_time"] >= 1000)
          device_count++;
        if (array[i]["run_time_ye"] >= 1000)
          device_count_ye++;
      }
      if (device_count > 0)
        run_time = parseInt(run_time / device_count);
      if (device_count_ye > 0)
        run_time_ye = parseInt(run_time_ye / device_count_ye);
      currentTime = parseInt(run_time * 100 / spantime + 0.5);
      if (currentTime > 100)
        currentTime = 100;
      let json = {};
      json["oee"] = currentTime;
      json["oee_ye"] = parseInt(run_time_ye * 100 / spantime_ye + 0.5);
      json["oee_all"] = parseInt((run_time + run_time_ye) * 100 / (spantime + spantime_ye) + 0.5);
      console.log('OEE 白班：' + run_time + '/' + spantime + ' = ' + json["oee"] + '，夜班：' + run_time_ye + '/' + spantime_ye + ' = ' + json["oee_ye"] + '，平均：' + json["oee_all"] + '，有效设备数目：' + device_count);
      if (json["oee_ye"] > 100)
        json["oee_ye"] = 100;
      if (json["oee_all"] > 100)
        json["oee_all"] = 100;
      currentTime = starttime;
      month = 12 * 3600 * 1000;
      while (currentTime < endtime) {
        dt.setTime(currentTime);
        if (dt.getDay() == 0) {
          if ((currentTime + 2 * month) <= endtime) {
            spantime -= month;
            spantime_ye -= month;
          }
          else {
            dt2.setTime(currentTime);
            setTime(dt2, 8);
            st = dt2.getTime();
            et = st + month;
            if (endtime <= st) {
              spantime_ye -= (endtime - currentTime);
            }
            else if (endtime <= et) {
              if (currentTime < st) {
                spantime_ye -= (st - currentTime);
                spantime -= (endtime - st);
              }
              else {
                spantime -= (endtime - currentTime);
              }
            }
            else {
              if (currentTime < st) {
                spantime_ye -= (st - currentTime);
                spantime -= month;
                spantime_ye -= (endtime - et);
              }
              else if (currentTime < et) {
                spantime -= (et - currentTime);
                spantime_ye -= (endtime - et);
              }
              else {
                spantime_ye -= (endtime - currentTime);
              }
            }
          }
          currentTime += 7 * 2 * month;
        }
        else {
          currentTime += 2 * month;
          dt2.setTime(currentTime);
          setTime(dt2, 8);
          currentTime = dt2.getTime();
        }
      }
      for (let i = 0; i < suc3.length; i++) {
        st = parseInt(suc3[i].starttime);
        et = parseInt(suc3[i].endtime);
        if (suc3[i].starttime.indexOf('-') > 0)
          st = Date.parse(suc3[i].starttime);
        if (suc3[i].endtime.indexOf('-') > 0)
          et = Date.parse(suc3[i].endtime);
        if (st >= endtime || et <= starttime) {
        }
        else {
          let flag = 1;
          if (suc3[i].status == "0") // 休假
            flag = -1;
          index = parseInt(suc3[i].hours);
          if (et > endtime) {
            index -= parseInt((et - endtime) / 3600000); // 这里可能存在着1个小时的误差
          }
          while (index >= 24) {
            spantime += month * flag;
            spantime_ye += month * flag;
            index -= 24;
          }
          dt.setTime(st);
          hour = dt.getHours();
          if (hour < 8) {
            if ((hour + index) < 8) {
              spantime_ye += index * 3600000 * flag;
            }
            else if ((hour + index) < 20) {
              spantime_ye += (8 - hour) * 3600000 * flag;
              spantime += (hour + index - 8) * 3600000 * flag;
            }
            else {
              spantime_ye += (8 - hour) * 3600000 * flag;
              spantime += month * flag;
              spantime_ye += (hour + index - 20) * 3600000 * flag;
            }
          }
          else if (hour < 20) {
            if ((hour + index) < 20) {
              spantime += index * 3600000 * flag;
            }
            else if ((hour + index) < 32) {
              spantime += (20 - hour) * 3600000 * flag;
              spantime_ye += (hour + index - 20) * 3600000 * flag;
            }
            else {
              spantime += (20 - hour) * 3600000 * flag;
              spantime_ye += month * flag;
              spantime += (hour + index - 32) * 3600000 * flag;
            }
          }
          else {
            if ((hour + index) < 32) {
              spantime_ye += (hour + index - 20) * 3600000 * flag;
            }
            else if ((hour + index) < 44) {
              spantime_ye += (32 - hour) * 3600000 * flag;
              spantime += (hour + index - 32) * 3600000 * flag;
            }
            else {
              spantime_ye += (32 - hour) * 3600000 * flag;
              spantime += month * flag;
              spantime_ye += (hour + index - 44) * 3600000 * flag;
            }
          }
        }
      }
      if (spantime < 1000) {
        console.log('spantime = ' + spantime);
        spantime = run_time;
        if (spantime < 1000)
          spantime = 1000;
      }
      if (spantime_ye < 1000) {
        console.log('spantime_ye = ' + spantime_ye);
        spantime_ye = run_time_ye;
        if (spantime_ye < 1000)
          spantime_ye = 1000;
      }
      json["oee15"] = parseInt(run_time * 100 / spantime + 0.5);
      json["oee15_ye"] = parseInt(run_time_ye * 100 / spantime_ye + 0.5);
      json["oee15_all"] = parseInt((run_time + run_time_ye) * 100 / (spantime + spantime_ye) + 0.5);
      console.log('OEE1.5 白班：' + run_time + '/' + spantime + ' = ' + json["oee15"] + '，夜班：' + run_time_ye + '/' + spantime_ye + ' = ' + json["oee15_ye"] + '，平均：' + json["oee15_all"]);
      if (json["oee15"] > 100)
        json["oee15"] = 100;
      if (json["oee15_ye"] > 100)
        json["oee15_ye"] = 100;
      if (json["oee_all"] > 100)
        json["oee_all"] = 100;
      temp.push(json);
    }
    res.status(200);
    res.json({ "result": "ok", "oee": temp });
  }
  catch (error) {
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//NOUSE
app.post('/QueryCncStatisticStatus', async (req, res) => {
  let date = new Date();
  console.log('QueryCncStatisticStatus from ' + req.ip + ' on ' + getMonthDayTime(date, 1, 1));
  let temp = new Array();
  let array = await StatisticUtilization(req.body.MachineName, req.body.starttime, req.body.endtime);
  for (let i = 0; i < array.length; i++) {
    let json = {};
    json["name"] = array[i]["name"];
    json["MachineName"] = array[i]["MachineName"];
    json["idle_time"] = parseInt(array[i]["idle_time"] / 36000 + 0.5) / 100;
    json["idle_count"] = array[i]["idle_count"];
    json["shutdown_time"] = parseInt(array[i]["shutdown_time"] / 36000 + 0.5) / 100;
    json["shutdown_count"] = array[i]["shutdown_count"];
    json["off_time"] = parseInt(array[i]["off_time"] / 36000 + 0.5) / 100;
    json["off_count"] = array[i]["off_count"];
    temp.push(json);
  }
  res.status(200);
  res.json({ "result": "ok", "status": temp });
})

let PdfToImage = function (file) {
  return new Promise((resolve, reject) => {
    let pdf2img = require('pdf2img');
    pdf2img.setOptions({
      type: 'png',
      size: 1024,
      density: 600,
      outputdir: path.dirname(file) + path.sep + 'images',
      outputname: 'page',
      page: null
    });
    let t1 = process.uptime();
    console.log('convert pdf to image:', file);
    pdf2img.convert(file, function (err, info) {
      if (err) {
        console.log('pdf2img failed, ' + err.message);
        let json = {};
        json["result"] = "fail";
        json["message"] = err.message;
        reject(json);
      }
      else {
        let t2 = process.uptime();
        console.log('pdf2img cost time ' + parseInt(t2 - t1) + ' sec: ' + file);
        resolve(info);
      }
    });
  });
}

async function ValidDesignFiles(unionorder, nextStep) {
  try {
    let ext = "";
    let index = 0, xls = 0, pdf = 0, stp = 0;
    let sql = "select * from machining_files where union_order = '" + unionorder + "' ORDER BY upload_time ASC";
    let suc2 = await db_util.query(sql);
    sql = "select type from autoschedule where union_order = '" + unionorder + "'";
    let suc = await db_util.query(sql);
    if (suc.length > 0) {
      let temp = suc[0]["type"].toUpperCase();
      if (temp == "PSE") {
        stp = 100;
      }
    }
    for (let i = 0; i < suc2.length; i++) {
      console.log(suc2[i].file_name + ': ' + suc2[i].file_status);
      if (suc2[i].file_status != 1)
        continue;
      sql = suc2[i].file_name.toLowerCase();
      index = sql.lastIndexOf('.');
      if (index < 1)
        continue;
      ext = sql.substr(index + 1);
      if (ext == 'xlsx' || ext == 'xls') {
        xls++;
      }
      else if (ext == 'pdf') {
        pdf++;
      }
      else if (ext == 'stp') {
        stp++;
      }
    }
    if (xls > 0 && pdf > 0 && stp > 0) {
      if (nextStep != undefined) {
        let date = new Date();
        sql = "update machining_union_sheet set stage = '0100000000', sheji_endtime = '" + getMonthDayTime(date, 1, 1) + "' where union_order = '" + unionorder + "'";
        await db_util.query(sql);
        sql = "update machining_sheet set status = '1' where union_order = '" + unionorder + "' and type_flag = 1";
        await db_util.query(sql);
      }
      console.log(unionorder + ' 可以送出');
      return "";
    }
    else {
      sql = "update machining_union_sheet set stage = '1000000000', sheji_endtime = '' where union_order = '" + unionorder + "'";
      await db_util.query(sql);
      sql = "update machining_sheet set status = '0' where union_order = '" + unionorder + "' and type_flag = 1";
      await db_util.query(sql);

      sql = "";
      if (stp == 0)
        sql = "stp文件";
      if (pdf == 0) {
        if (sql != '')
          sql += "、";
        sql += "pdf文件";
      }
      if (xls == 0) {
        if (sql != '')
          sql += "、";
        sql += "xlsx文件";
      }
      sql += "没有上传或没有通过审核";
      console.log(sql);
      return sql;
    }
  }
  catch (error) {
    console.log('ValidDesignFiles error: ' + error.message);
    return error.message;
  }
}

async function ParsePdfFile(unionorder, file, imageNo) {
  let cost_time = Date.now();
  try {
    let sql = "select id, sheet_order from machining_sheet where quatity != '0' and union_order = '" + unionorder + "' and type_flag = '1'";
    let suc = await db_util.query(sql);
    if (suc.length == 0) // BOM表有没有导入
    {
      console.log('BOM表没有导入或没有加工件');
      return;
    }
    let arr = new Array();
    if (unionorder == file) // from ParseBOMFile
    {
      sql = "select id, name from machining_union_sheet where union_order = '" + unionorder + "'";
      let succ3 = await db_util.query(sql);
      if (succ3.length > 0) {
        sql = "select * from machining_files where union_order = '" + unionorder + "' and sheet_order = '" + succ3[0]['name'] + "' ORDER BY upload_time ASC";
        let succ2 = await db_util.query(sql);
        let i, k, m = 0, temp = "";
        for (i = 0; i < succ2.length; i++) {
          k = succ2[i]['file_name'].lastIndexOf('.');
          if (k < 1) {
            console.log(succ2[i]['file_name']);
            continue;
          }
          temp = succ2[i]['file_name'].substr(k).toLowerCase();
          if (temp != '.pdf')
            continue;
          m++;
          if (succ2[i]['file_status'] != 1)
            continue;
          arr.push(succ2[i]['file_path']);
        }
        if (m == 0) {
          console.log(unionorder + ' - ' + succ3[0]['name'] + '：没有找到图档PDF文件（还没有上传吧？）');
        }
        else if (arr.length == 0) {
          console.log(unionorder + ' - ' + succ3[0]['name'] + '：图档PDF文件没有通过审核');
        }
      }
      else {
        console.log('没有找到工联单号', sql);
      }
    }
    else {
      arr.push(file);
    }

    for (let m = 0; m < arr.length; m++) {
      file = arr[m];
      if (!fs.existsSync(file)) {
        console.log("not find the file: " + file);
        continue;
      }
      let info = await PdfToImage(file);
      if (info["result"] != "success") {
        continue;
      }
      let PDFToTextJS = require('pdftotextjs');
      let iconv = require('encoding');
      let i = 0, j = 0, k = 0, page = 0;
      let lastpage = info.message.length;
      let array = new Array(info.message.length);
      for (i = 0; i < info.message.length; i++) {
        array[i] = null;
        page = i + 1;
        let pdf = new PDFToTextJS(file);
        pdf.add_options(['-f ' + page, '-l ' + page]);
        try {
          let data = pdf.getTextSync();
          if (data != undefined) {
            /*let newdata = iconv.convert(data, 'GBK'); // utf8 => GBK
            let filepath = './public/' + unionorder + '/' + page + '.txt';
            fs.writeFileSync(filepath, newdata);*/
            array[i] = data.toString().toUpperCase();
          }
        }
        catch (err) {
          console.log('PdfToText failed at page ' + page + ', ' + err.message);
        }
        pdf = null;
      }
      for (i = 0; i < suc.length; i++) {
        let sheet_order = suc[i].sheet_order.toUpperCase();
        let buffer = Buffer.alloc(sheet_order.length * 2);
        for (j = 0; j < sheet_order.length; j++) {
          k = sheet_order.charCodeAt(j);
          buffer[j * 2] = 0xA3;
          if (k > 0xFF00)
            buffer[j * 2 + 1] = k - 0xFF00 + 0xA0;
          else if (k < 0x80)
            buffer[j * 2 + 1] = 0x80 + k;
          else {
            let temp = k.toString(16);
            buffer[j * 2] = parseInt(temp.substr(0, 2), 16);
            buffer[j * 2 + 1] = parseInt(temp.substr(2, 2), 16);
            if (j == sheet_order.length - 1)
              console.log(temp + '是Unicode，不是GBK，无法转成UTF8', buffer);
          }
        }
        let temp = iconv.convert(buffer, "UTF8", "GBK");
        j = i + 5;
        if (j >= info.message.length)
          j = info.message.length - 1;
        for (; j >= 0; j--) {
          if (array[j] == null)
            continue;
          page = j + 1;
          k = array[j].indexOf(temp);
          if (j == 0 && k < 0 && info.message.length == suc.length) {
            console.log('按页码匹配图片：' + (i + 1));
            k = 1;
            j = i;
          }
          if (k > 0) {
            let imagepath = "";
            if ((page - lastpage) > 1) {
              for (k = lastpage + 1; k <= page; k++) {
                sql = info.message[k - 1].path.substr(9); // 去掉./public/
                imagepath += sql;
                if (k < page)
                  imagepath += ',';
              }
            }
            else {
              imagepath = info.message[j].path.substr(9);
            }
            console.log(suc[i].sheet_order + '对应的图片是 ' + imagepath);
            sql = "update machining_sheet set imagefile = '" + imagepath + "'";
            k = array[j].indexOf('&');
            if (k > 0)
              sql += ", bom_remark = 'V'";
            else
              sql += ", bom_remark = ''";
            sql += " where id = '" + suc[i].id + "'";
            await db_util.query(sql);
            if (k > 0) // 重点尺寸标记
            {
              console.log('重点尺寸标记', sql);
            }
            j = -100;
            lastpage = page;
          }
        }
        if (j == -1) {
          console.log(suc[i].sheet_order + ' 没有对应的图片');
        }
        buffer = null;
      }
    }
    array = null;
    i = await ValidDesignFiles(unionorder);
    cost_time = Date.now() - cost_time;
    console.log('ParsePdfFile cost time: ' + parseInt(cost_time / 1000) + ' sec');
  }
  catch (error) {
    console.log('ParsePdfFile error: ' + error.message);
  }
}

//NOUSE
app.post('/DebugTest', async (req, res) => {
  if (req.body.sql == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not find sql command line" });
    return;
  }
  console.log('DebugTest ' + req.ip, req.body);
  try {
    let sucData = await db_util.query(req.body.sql);
    let json = {};
    let array = new Array();
    if (sucData.length > 0) {
      sucData.forEach(element => {
        array.push(element);
      });
    }
    json["result"] = "ok";
    json["values"] = array;
    json["description"] = sucData.message;
    res.status(200);
    res.json(json);
  }
  catch (err) {
    res.status(200);
    res.json({ "result": "error", "description": err.message, "sql": req.body.sql });
  }
})

async function kafkaTest() {
  //console.log('kafka fetch message...');
  try {
    var errormsg = "";
    let kafka2ClientMap = []
    const CONSUMER = 'consumer';
    let KafkaConfig = db_util.config.kafka2

    const OFFSET = require('./Kafka/kafka-manager.js').OFFSET;

    const KafkaManager = require('./Kafka/kafka-manager.js').KafkaManager;


    let username = KafkaConfig.KafkaTopics.username;
    let password = KafkaConfig.KafkaTopics.password;
    let topicName = KafkaConfig.KafkaTopics.topic;
    let kafkaClients = kafka2ClientMap.filter(e => e.username == username && e.type == CONSUMER)

    if (kafkaClients.length == 0) {
      kafka2ClientMap.push({
        username: username,
        password: password,
        type: CONSUMER,
        topics: [topicName]
      })
    } else {
      kafkaClients[0].topics.push(topicName)
    }


    kafka2ClientMap.forEach(kafkaClient => {
      let username = kafkaClient.username;
      let password = kafkaClient.password;
      let topics = kafkaClient.topics;

      if (!kafkaClient.kafkaManager) {
        let km = new KafkaManager(KafkaConfig.KafkaURL, username, password, KafkaConfig.SchemaRegistryHost);
        let kafkaClientByUser = kafka2ClientMap.filter(e => e.username == username);
        kafkaClientByUser.forEach(e => {
          e.kafkaManager = km;
        })
      }
      let kfmgr = kafkaClient.kafkaManager
      console.log(kafkaClient.type);

      if (kafkaClient.type == CONSUMER) {
        let groupId = KafkaConfig.KafkaClient + '-' + username
        console.log(groupId);
        kafkaClient.client = kfmgr.setConsumer(groupId, topics, true, OFFSET.latest,
          (msg) => {
            console.log(msg);
            let date = new Date();
            console.log('Fetch e-form data from Kafka on ' + getMonthDayTime(date, 1, 1));
            let objs = JSON.parse(msg.value);
            console.log(objs);
            let sql = "select * from p79_tofsms where UniqueID = '" + objs.id + "'";
            let applyDate =  objs.applyDate + ' 00:00:00.000';
            let requireDate = objs.requireDate + ' 00:00:00.0';
            db_util.ExecuteSQL(sql, null,
              (sucData) => {
                if (sucData.length == 0) {
                  sql = "insert into p79_tofsms values(null \
              , '"+ objs.id + "', '" + objs.ProductionID + "', '" + objs.applicationID + "', '" + objs.applicantID + "' \
              , '"+ objs.applicant + "', '" + applyDate + "', '" + objs.dept + "', '" + objs.area + "' \
              , '"+ objs.contact + "', '" + objs.chargeDept + "', '" + objs.area + "', '' \
              , '', '', '" + objs.Specification + "', '" + objs.Specification + "' \
              , '"+ objs.toolname + "', '" + objs.partNo + "', '" + objs.quantity + "', '" + objs.madeType + "', '" + objs.materialDemand + "' \
              , '"+ objs.machineCategory + "', '" + requireDate + "', '" + requireDate + "', '" + getMonthDayTime(date, 1, 1) + "')";
                  db_util.ExecuteSQL(sql, null,
                    (suc2) => {
                      console.log('insert into p79_tofsms ' + suc2.affectedRows + ', ID: ' + suc2.insertId);

                      date.setTime(Date.parse(requireDate));//CompleteDay
                      let RequestDate = getMonthDayTime(date, 1);
                      sql = "select * from machining_union_sheet where union_order = '" + objs.ProductionID + "'";
                      db_util.ExecuteSQL(sql, null,
                        (suc4) => {
                          if (suc4.length == 0) {
                            sql = "insert into machining_union_sheet (union_order, name, quatity, delivery_date, apply_person, applyDeptPIC,\
                          charge_department, delivery_addr, factory, machine_type, p79_id) values ('"+ objs.ProductionID + "', '" + objs.toolname + "',\
                          '"+ objs.quantity + "', '" + RequestDate + "', '" + objs.applicant + "', '',\
                          '"+ objs.chargeDept + "', '" + objs.area + "', '" + objs.area + "', '" + objs.machineCategory + "', '" + suc2.insertId + "')";
                            db_util.ExecuteSQL(sql, null,
                              (suc3) => {
                                console.log('insert into machining_union_sheet ' + suc3.affectedRows + ', ID: ' + suc3.insertId);
                              },
                              (err3) => {
                                console.log('Insert machining_union_sheet failed, ' + err3.message);
                                console.log(sql);
                              }
                            );
                          }
                          else {
                            console.log('The union_order existed already');
                            console.log(sql);
                            let flag = false;
                            sql = "update machining_union_sheet set ";
                            if (suc4[0]["name"] != objs.toolname) {
                              if (flag)
                                sql += ", ";
                              flag = true;
                              sql += "name = '" + objs.toolname + "'";
                            }
                            if (suc4[0]["quatity"] != objs.quantity) {
                              if (flag)
                                sql += ", ";
                              flag = true;
                              sql += "tip = '" + suc4[0]["quatity"] + "', quatity = '" + objs.quantity + "'";
                            }
                            if (suc4[0]["delivery_date"] != RequestDate) {
                              if (flag)
                                sql += ", ";
                              flag = true;
                              sql += "delivery_date = '" + RequestDate + "'";
                            }
                            if (suc4[0]["delivery_addr"] != objs.area) {
                              if (flag)
                                sql += ", ";
                              flag = true;
                              sql += "delivery_addr = '" + objs.area + "'";
                            }
                            if (suc4[0]["charge_department"] != objs.chargeDept) {
                              if (flag)
                                sql += ", ";
                              flag = true;
                              sql += "charge_department = '" + objs.chargeDept + "'";
                            }
                            if (flag) {
                              sql += " where union_order = '" + objs.ProductionID + "'";
                              db_util.ExecuteSQL(sql, null,
                                (suc5) => {
                                  console.log('Succeeded to update machining_union_sheet ' + suc5.affectedRows);
                                  console.log(sql);
                                },
                                (err5) => {
                                  console.log('Failed to update machining_union_sheet, ' + err5.message);
                                  console.log(sql);
                                }
                              );
                            }
                          }
                        },
                        (err4) => {
                          console.log('Query machining_union_sheet failed, ' + err4.message);
                          console.log(sql);
                        }
                      );
                    },
                    (err2) => {
                      console.log('Insert p79_tofsms failed, ' + err2.message);
                      console.log(sql);
                    }
                  );
                }
                else {
                  console.log('The UniqueID existed already');
                  console.log(sql);
                }
              },
              (errData) => {
                console.log('Query p79_tofsms failed, ' + errData.message);
              }
            );

          },
          (err) => {
            if (errormsg != err) {
              errormsg = err;
              let date = new Date();
              console.log('Kafka报错：' + getMonthDayTime(date, 1, 1) + errormsg);
              //console.log(err);
            }
          })
      }
    })
    
    // 舊備份
    // kafka2ClientMap.forEach(kafkaClient => {
    //   let username = kafkaClient.username;
    //   let password = kafkaClient.password;
    //   let topics = kafkaClient.topics;

    //   if (!kafkaClient.kafkaManager) {
    //     let km = new KafkaManager(KafkaConfig.KafkaURL, username, password, KafkaConfig.SchemaRegistryHost);
    //     let kafkaClientByUser = kafka2ClientMap.filter(e => e.username == username);
    //     kafkaClientByUser.forEach(e => {
    //       e.kafkaManager = km;
    //     })
    //   }
    //   let kfmgr = kafkaClient.kafkaManager

    //   if (kafkaClient.type == CONSUMER) {
    //     let groupId = KafkaConfig.KafkaClient + '-' + username
    //     kafkaClient.client = kfmgr.setConsumer(groupId, topics, true, OFFSET.latest,
    //       (msg) => {
    //         let date = new Date();
    //         console.log('Fetch e-form data from Kafka on ' + getMonthDayTime(date, 1, 1));
    //         let objs = JSON.parse(msg.value);
    //         let sql = "select * from p79_tofsms where UniqueID = '" + objs.UniqueID + "'";
    //         db_util.ExecuteSQL(sql, null,
    //           (sucData) => {
    //             if (sucData.length == 0) {
    //               sql = "insert into p79_tofsms values(null \
    //           , '"+ objs.UniqueID + "', '" + objs.WorkOrder + "', '" + objs.SequenceID + "', '" + objs.ApplyID + "' \
    //           , '"+ objs.ApplyName + "', '" + objs.ApplyDateTime + "', '" + objs.ApplyerDeptID + "', '" + objs.Location + "' \
    //           , '"+ objs.PIC + "', '" + objs.ChargeDept + "', '" + objs.Area + "', '" + objs.RequestOwnerID + "' \
    //           , '"+ objs.RequestOwnerName + "', '" + objs.RequestOwnerTel + "', '" + objs.ExpectOFileName + "', '" + objs.ExpecteFileName + "' \
    //           , '"+ objs.ToolName + "', '" + objs.ToolTrNO + "', '" + objs.ToolNum + "', '" + objs.ToolWay + "', '" + objs.ToolRemark + "' \
    //           , '"+ objs.Machine + "', '" + objs.RequestDate + "', '" + objs.CompleteDay + "', '" + getMonthDayTime(date, 1, 1) + "')";
    //               db_util.ExecuteSQL(sql, null,
    //                 (suc2) => {
    //                   console.log('insert into p79_tofsms ' + suc2.affectedRows + ', ID: ' + suc2.insertId);

    //                   date.setTime(Date.parse(objs.CompleteDay));
    //                   let RequestDate = getMonthDayTime(date, 1);
    //                   sql = "select * from machining_union_sheet where union_order = '" + objs.WorkOrder + "'";
    //                   db_util.ExecuteSQL(sql, null,
    //                     (suc4) => {
    //                       if (suc4.length == 0) {
    //                         sql = "insert into machining_union_sheet (union_order, name, quatity, delivery_date, apply_person, applyDeptPIC,\
    //                       charge_department, delivery_addr, factory, machine_type, p79_id) values ('"+ objs.WorkOrder + "', '" + objs.ToolName + "',\
    //                       '"+ objs.ToolNum + "', '" + RequestDate + "', '" + objs.ApplyName + "', '" + objs.RequestOwnerName + "',\
    //                       '"+ objs.ChargeDept + "', '" + objs.Area + "', '" + objs.Location + "', '" + objs.Machine + "', '" + suc2.insertId + "')";
    //                         db_util.ExecuteSQL(sql, null,
    //                           (suc3) => {
    //                             console.log('insert into machining_union_sheet ' + suc3.affectedRows + ', ID: ' + suc3.insertId);
    //                           },
    //                           (err3) => {
    //                             console.log('Insert machining_union_sheet failed, ' + err3.message);
    //                             console.log(sql);
    //                           }
    //                         );
    //                       }
    //                       else {
    //                         console.log('The union_order existed already');
    //                         console.log(sql);
    //                         let flag = false;
    //                         sql = "update machining_union_sheet set ";
    //                         if (suc4[0]["name"] != objs.ToolName) {
    //                           if (flag)
    //                             sql += ", ";
    //                           flag = true;
    //                           sql += "name = '" + objs.ToolName + "'";
    //                         }
    //                         if (suc4[0]["quatity"] != objs.ToolNum) {
    //                           if (flag)
    //                             sql += ", ";
    //                           flag = true;
    //                           sql += "tip = '" + suc4[0]["quatity"] + "', quatity = '" + objs.ToolNum + "'";
    //                         }
    //                         if (suc4[0]["delivery_date"] != RequestDate) {
    //                           if (flag)
    //                             sql += ", ";
    //                           flag = true;
    //                           sql += "delivery_date = '" + RequestDate + "'";
    //                         }
    //                         if (suc4[0]["delivery_addr"] != objs.Area) {
    //                           if (flag)
    //                             sql += ", ";
    //                           flag = true;
    //                           sql += "delivery_addr = '" + objs.Area + "'";
    //                         }
    //                         if (suc4[0]["charge_department"] != objs.ChargeDept) {
    //                           if (flag)
    //                             sql += ", ";
    //                           flag = true;
    //                           sql += "charge_department = '" + objs.ChargeDept + "'";
    //                         }
    //                         if (flag) {
    //                           sql += " where union_order = '" + objs.WorkOrder + "'";
    //                           db_util.ExecuteSQL(sql, null,
    //                             (suc5) => {
    //                               console.log('Succeeded to update machining_union_sheet ' + suc5.affectedRows);
    //                               console.log(sql);
    //                             },
    //                             (err5) => {
    //                               console.log('Failed to update machining_union_sheet, ' + err5.message);
    //                               console.log(sql);
    //                             }
    //                           );
    //                         }
    //                       }
    //                     },
    //                     (err4) => {
    //                       console.log('Query machining_union_sheet failed, ' + err4.message);
    //                       console.log(sql);
    //                     }
    //                   );
    //                 },
    //                 (err2) => {
    //                   console.log('Insert p79_tofsms failed, ' + err2.message);
    //                   console.log(sql);
    //                 }
    //               );
    //             }
    //             else {
    //               console.log('The UniqueID existed already');
    //               console.log(sql);
    //             }
    //           },
    //           (errData) => {
    //             console.log('Query p79_tofsms failed, ' + errData.message);
    //           }
    //         );

    //       },
    //       (err) => {
    //         if (errormsg != err) {
    //           errormsg = err;
    //           let date = new Date();
    //           console.log('Kafka报错：' + getMonthDayTime(date, 1, 1));
    //           //console.log(err);
    //         }
    //       })
    //   }
    // })
  }
  catch (error) {
    console.log('Kafka exception: ' + error.message);
  }
}

//FSMS
async function ParseWarehouseFile(filePath) {
  let cost_time = Date.now();
  let array = new Array();
  let i = filePath.lastIndexOf('.');
  try {
    if (i > 1) {
      let sql = filePath.substr(i + 1).toLowerCase();
      if (sql == 'xlsx' || sql == 'xls') {
        let obj = xlsx.parse(filePath);
        for (i = 0; i < obj.length; i++) {
          if (obj[i].data[0][0] == 'PR NO') {
            let flag = false;
            let k = 0, j = 0;
            let date = new Date();
            let timestamp = getMonthDayTime(date, 1, 1);
            let data = new Array();
            let quatity = 0.0, qty_temp = 0.0;
            for (j = 1; j < obj[i].data.length; j++) {
              flag = false;
              sql = "select * from base_material where material_no = '" + obj[i].data[j][3] + "'";
              let suc1 = await db_util.query(sql);
              if (suc1.length > 0) {
                sql = "select * from firm_info where fullname = '" + obj[i].data[j][6] + "'";
                let suc2 = await db_util.query(sql);
                if (suc2.length > 0)
                  flag = true;
                else
                  console.log('厂商信息表中没有 ' + obj[i].data[j][6] + ' ~ ' + obj[i].data[j][3]);
              }
              else {
                console.log('备品信息表中没有 ' + obj[i].data[j][3]);
              }
              if (flag) {
                let temp = new Array(13);
                temp[0] = null;
                for (k = 0; k < 10; k++) {
                  temp[k + 1] = obj[i].data[j][k];
                  if (k > 7 && temp[k + 1] == undefined)
                    temp[k + 1] = "";
                }
                temp[k + 1] = timestamp;
                temp[k + 2] = '0';
                data.push(temp);
                quatity = parseFloat(suc1[0].stock);
                if (isNaN(quatity))
                  quatity = 0;
                qty_temp = parseFloat(obj[i].data[j][4]);
                if (isNaN(qty_temp))
                  qty_temp = 0;
                qty_temp += quatity;
                quatity = dotFixed(qty_temp, 3);
                sql = "update base_material set stock = '" + quatity + "' where material_no = '" + obj[i].data[j][3] + "'";
                await db_util.query(sql);
              }
              else {
                quatity = parseFloat(obj[i].data[j][4]); // quatity
                if (isNaN(quatity))
                  quatity = 0;
                qty_temp = parseFloat(obj[i].data[j][5]); // price
                if (isNaN(qty_temp))
                  qty_temp = 0;
                let json = {};
                json["PR_NO"] = obj[i].data[j][0];
                json["PO_NO"] = obj[i].data[j][1];
                json["SN"] = obj[i].data[j][2];
                json["material_no"] = obj[i].data[j][3];
                json["quatity"] = dotFixed(quatity, 3);
                json["price"] = dotFixed(qty_temp, 3);
                json["manufacturer"] = obj[i].data[j][6];
                json["currency"] = obj[i].data[j][7];
                json["check_no"] = obj[i].data[j][8];
                json["reason"] = obj[i].data[j][9];
                array.push(json);
              }
            }
            if (data.length > 0) {
              sql = "insert into warehouse values ?"
              let suc = await db_util.query(sql, [data]);
              cost_time = Date.now() - cost_time;
              console.log('ParseWarehouseFile cost time ' + cost_time + ', ' + suc.message);
            }
            break;
          }
        }
      }
    }
  }
  catch (error) {
    console.log('ParseWarehouseFile error: ' + error.message);
  }
  return array;
}

//FSMS
async function CheckBOMFile(bomFile, unionorder) {
  try {
    if (!fs.existsSync(bomFile)) {
      return "文件不存在";
    }
    let i = bomFile.lastIndexOf('.');
    if (i < 1) {
      return "";
    }
    else {
      let ext = bomFile.substr(i + 1).toLowerCase();
      if (ext != 'xlsx' && ext != 'xls') {
        return "";
      }
    }
    console.log('CheckBOMFile: ' + bomFile);
    let ret = "";
    let temp = "";
    let jiagongjianshu = -1;
    let gongjianzongshu = -1;
    let array = new Array(); // 保存加工单号，比对是否有工单号重复的情况
    let obj = xlsx.parse(bomFile);
    for (i = 0; i < obj.length; i++) {
      if (obj[i].name.indexOf("BOM") >= 0) {
        jiagongjianshu = 0;
        gongjianzongshu = 0;
        break;
      }
    }
    if (i < obj.length) {
      let k, m;
      let j = 6;
      let sql = "";
      let addAll = true;
      let order = obj[i].data[1][15];
      if (order != unionorder) {
        ret = "BOM表中工聯單號錯誤。";
        console.log('CheckBOMFile result: ' + ret);
        return ret;
      }
      for (k = 6; k < obj[i].data.length; k++) {
        if (obj[i].data[k][7] == "是") {
          addAll = false;
          break;
        }
      }
      for (k = 6; k < obj[i].data.length; k++) {
        // obj[i].data[k][]列表中：0/序号；1/类型（加工件还是标准件）；2/加工件图号或标准件名称；3/长；4/宽；5/高；6/料号；7/是否新增；
        // 8/材质；9/密度；10/用量（单台）；11/需求总量；12/总重量；13/发料员；14/重点尺寸；15/备注
        if (obj[i].data[k][j] == null)
          continue;
        if (obj[i].data[k][j].length == 0)
          continue;
        if (addAll == false) {
          if (obj[i].data[k][7] != "是")
            continue;
        }
        gongjianzongshu++;
        if (obj[i].data[k][1] == "加工件") {
          jiagongjianshu += 1;
          for (m = 0; m < array.length; m++) {
            if (array[m] == obj[i].data[k][2]) {
              break;
            }
          }
          if (m == array.length) {
            array.push(obj[i].data[k][2]);
          }
        }

        sql = "select * from base_material where material_no = '" + obj[i].data[k][j] + "'";
        let suc = await db_util.query(sql);
        if (suc.length == 0) {
          if (ret.length > 0) {
            if (ret.indexOf(obj[i].data[k][j]) < 0) {
              ret += "、";
              ret += obj[i].data[k][j];
            }
          }
          else {
            ret = obj[i].data[k][j];
          }
        }
        let flag = false;
        if (obj[i].data[k][10] == null)
          flag = true;
        else if (obj[i].data[k][10].length == 0)
          flag = true;
        else if (obj[i].data[k][11] == null)
          flag = true;
        else if (obj[i].data[k][11].length == 0)
          flag = true;
        if (flag == true) {
          if (temp.length > 0)
            temp += "、";
          temp += obj[i].data[k][2];
        }
      }
    }
    if (ret.length > 0 || temp.length > 0) {
      if (ret.length > 0) {
        sql = ret;
        ret = "料號：" + sql + "不存在。";
      }
      if (temp.length > 0) {
        sql = temp + "的用量或需求总量没有设置。";
        ret += sql;
      }
      console.log('CheckBOMFile result: ' + ret);
    }
    if (gongjianzongshu == 0) {
      ret = "BOM表中没有加工件和标准件。";
      console.log('CheckBOMFile result: ' + ret);
    }
    else if (jiagongjianshu > 0 && jiagongjianshu > array.length) {
      ret = "BOM表中加工件图号不可以重复。";
      console.log('CheckBOMFile result: ' + ret);
    }
    if (ret.length == 0) {
      console.log('CheckBOMFile result: OK');
    }
    return ret;
  }
  catch (error) {
    console.log('CheckBOMFile error: ' + error.message);
    return "";
  }
}

function BOMItemValidCheck(item) {
  if (item[1] == null) // 类型为空
    return false;
  if (item[1].length == 0)
    return false;
  if (item[2] == null) // 图号/名称为空
    return false;
  if (item[2].length == 0)
    return false;
  if (item[6] == null) // 料号为空
    return false;
  if (item[6].length == 0)
    return false;
  if (item[10] == null) // 用量为空
    return false;
  if (item[10].length == 0)
    return false;
  if (item[11] == null) // 需求总量为空
    return false;
  if (item[11].length == 0)
    return false;
  return true;
}

//FSMS
async function ParseBOMFile(bomFile) {
  let sql = "";
  let order = "";
  try {
    if (!fs.existsSync(bomFile)) {
      console.log('ParseBOMFile error, the file does not exist: ' + bomFile);
      return "the file does not exist";
    }
    let i = bomFile.lastIndexOf('.');
    if (i < 1) {
      console.log('ParseBOMFile error, the file is not excel file: ' + bomFile);
      return "the file is not excel file";
    }
    else {
      let ext = bomFile.substr(i + 1).toLowerCase();
      if (ext != 'xlsx' && ext != 'xls') {
        console.log('ParseBOMFile error, the file is not excel file: ' + bomFile);
        return "the file is not excel file";
      }
    }
    console.log('ParseBOMFile: ' + bomFile);
    let ret = "ok";

    let obj = xlsx.parse(bomFile);
    for (i = 0; i < obj.length; i++) {
      if (obj[i].name.indexOf("BOM") >= 0) {
        break;
      }
    }
    if (i < obj.length) {
      order = obj[i].data[1][15];
      let quatity = obj[i].data[1][6];
      let name = "";
      let factory = "";
      let imageNo = obj[i].data[3][9];
      console.log('图档文件名：' + imageNo);
      let jiagongjianshu = 0;
      let gongjianzongshu = 0;
      let addAll = true;
      let j = 0, k = 0;
      sql = "select name, factory from machining_union_sheet where union_order = '" + order + "'";
      let sucData = await db_util.query(sql);
      if (sucData.length == 0) {
        console.log('ParseBOMFile failed, the order does not exist');
        return "the order does not exist";
      }
      else {
        name = sucData[0].name;
        factory = sucData[0].factory;
      }

      j = 0;
      for (k = 6; k < obj[i].data.length; k++) {
        if (BOMItemValidCheck(obj[i].data[k]) == false)
          continue;
        gongjianzongshu++;
        if (obj[i].data[k][7] == "是")
          j++;
      }
      if (j > 0 && j < gongjianzongshu)
        addAll = false;

      gongjianzongshu = 0;
      for (k = 6; k < obj[i].data.length; k++) {
        if (BOMItemValidCheck(obj[i].data[k]) == false)
          continue;
        if (addAll == false) {
          if (obj[i].data[k][7] != "是")
            continue;
        }
        gongjianzongshu++;
        if (obj[i].data[k][1] == "加工件")
          jiagongjianshu += 1;
      }
      if (gongjianzongshu == 0)//|| jiagongjianshu == 0 )
      {
        console.log(bomFile + '工件总数或加工件数为0');
        return "工件总数或加工件数为0";
      }

      let cnc = new Array(jiagongjianshu);
      jiagongjianshu = 0;
      let data = new Array(gongjianzongshu);
      gongjianzongshu = 0;
      for (k = 6; k < obj[i].data.length; k++) {
        if (BOMItemValidCheck(obj[i].data[k]) == false)
          continue;
        if (addAll == false) {
          if (obj[i].data[k][7] != "是")
            continue;
        }
        let temp = new Array(16);
        temp[0] = order; // 工联单号
        for (j = 1; j < obj[i].data[1].length; j++) {
          if (j == 13) // 屏蔽掉发料员字段
            continue;
          if (obj[i].data[k][j] == null) {
            sql = "";
          }
          else {
            if (j == 12)
              sql = dotFixed(obj[i].data[k][j]);
            else
              sql = obj[i].data[k][j];

          }
          if (j < 7) // 7是是否新增字段
            temp[j] = sql;
          else if (j > 7 && j < 13)
            temp[j - 1] = sql;
          else if (j == 14) // 15是备注，也屏蔽掉
            temp[12] = sql;
        }
        // temp[1]: 类型，标准件还是加工件; temp[2]: 标准件名称或加工件图号
        // temp[3/4/5]: length/width/height; temp[6]: material_no; temp[7]: stuff;
        // temp[8]: density; temp[9]: quatity; temp[10]: quatity_total; temp[11]: weight
        // temp[12]: bom_remark(重点尺寸标记)
        // temp[13]: stuff2; temp[14]: type_flag; temp[15]: status
        let count = parseFloat(temp[9]) * parseInt(quatity);
        if (parseFloat(temp[10]) != count)
          temp[10] = dotFixed(count, 3);//count.toString();
        if (temp[1] == "加工件") {
          if (temp[12].indexOf("V") >= 0 || temp[12].indexOf("v") >= 0) // 重點尺寸/重点尺寸 => V/v
            temp[12] = "V";
          else
            temp[12] = "";
          let result = getcnc(temp[7], temp[3], temp[4], temp[10]);
          temp[13] = temp[7]; // stuff2是从BOM导入的材质
          temp[14] = "1";
          temp[15] = "0"; // 0/设计；1/编程；2/加工；3/品检；4/二次加工；5/组装；6/总检；7/入库，解析了PDF文件之后再改为1
          sql = "select * from base_material where material_no = '" + obj[i].data[k][6] + "'";
          let suc = await db_util.query(sql);
          if (suc.length > 0 && suc[0].name != '') {
            temp[7] = suc[0].name;
          }

          let cncTemp = new Array(10);
          cncTemp[0] = order; // 工联单号
          cncTemp[1] = name; // 治具名称
          cncTemp[2] = factory; // 厂别
          cncTemp[3] = temp[2]; // 零件名称
          if (temp[3] == "") {
            cncTemp[4] = ""; // 图纸尺寸
          }
          else {
            if (temp[3][0] == 'D' || temp[3][0] == 'd')
              cncTemp[4] = temp[3] + '*' + temp[5];
            else
              cncTemp[4] = temp[3] + '*' + temp[4] + '*' + temp[5];
          }
          cncTemp[5] = temp[7]; // 材质
          cncTemp[6] = temp[11]; // 总重量
          cncTemp[7] = '1'; // 原始数据
          cncTemp[8] = temp[10]; // 工件总数量
          cncTemp[9] = temp[6];  // 料号
          cncTemp[10] = result["name"]; // cnc
          cnc[jiagongjianshu++] = cncTemp;
        }
        else {
          temp[13] = "";
          temp[14] = "0";
          temp[15] = "5"; // 直接进入组装状态
        }
        data[gongjianzongshu++] = temp;
      }
      sql = "select * from machining_sheet where quatity != '0' and union_order = '" + order + "'";
      let succ3 = await db_util.query(sql);
      if (succ3.length == 0 || addAll == false) {
        sql = "insert into machining_sheet (union_order, type, sheet_order, size_length, size_width, size_height, material_no, stuff, density, quatity, quatity_total, weight, bom_remark, stuff2, type_flag, status) values ?";
        let succ = await db_util.query(sql, [data]);
        if (succ.affectedRows > 0) {
          if (cnc.length > 0) {
            sql = "insert into dispatch_sheet (union_order, name, factory, ljmc, tzcc, czhi, zhl, rawdata, gjsl, material_no, cnc) values ?";
            let succ2 = await db_util.query(sql, [cnc]);
            if (succ2.affectedRows > 0) {
              setTimeout(function () { ParsePdfFile(order, order, imageNo); }, 1000);
              console.log('ParseBOMFile succeeded.');
            }
            else {
              sql = "delete from machining_sheet where quatity != '0' and union_order = '" + order + "'";
              await db_util.query(sql);
              console.log('ParseBOMFile failed to insert dispatch sheet ~');
              ret = "failed to insert dispatch sheet ~";
            }
          }
          else {
            console.log(order + ' 没有加工件，直接进组装');
            sql = "update machining_union_sheet set stage = '0000010000' where union_order = '" + order + "'";
            await db_util.query(sql);
          }
        }
        else {
          console.log('ParseBOMFile failed to insert sheet table, so delete order from union sheet table');
          ret = "failed to insert sheet table";
        }
      }
      else {
        gongjianzongshu = 0;
        let temp = new Array(); // 表machining_sheet中已更新的记录ID
        for (k = 0; k < data.length; k++) {
          for (j = 0; j < succ3.length; j++) {
            if (succ3[j].sheet_order == data[k][2]) {
              gongjianzongshu++;
              temp.push(succ3[j].id);

              if (data[k][14] == "1") // 加工件
              {
                sql = "update machining_sheet set size_length = '" + data[k][3] + "', size_width = '" + data[k][4] + "', size_height = '" + data[k][5] + "',\
                      material_no = '"+ data[k][6] + "', stuff = '" + data[k][7] + "', density = '" + data[k][8] + "',\
                      quatity = '"+ data[k][9] + "', quatity_total = '" + data[k][10] + "', weight = '" + data[k][11] + "',\
                      bom_remark = '"+ data[k][12] + "', type = '" + data[k][1] + "', type_flag = '" + data[k][14] + "' where id = '" + succ3[j].id + "'";
              }
              else {
                sql = "update machining_sheet set material_no = '" + data[k][6] + "', quatity = '" + data[k][9] + "', quatity_total = '" + data[k][10] + "',\
                      bom_remark = '"+ data[k][12] + "', type = '" + data[k][1] + "', type_flag = '" + data[k][14] + "' where id = '" + succ3[j].id + "'";
              }
              await db_util.query(sql);
              if (data[k][14] == "1") // 加工件，更新dispatch_sheet
              {
                let m = j;
                for (j = 0; j < cnc.length; j++) {
                  if (cnc[j][3] == data[k][2]) {
                    if (succ3[m]['type_flag'] != data[k][14]) // 以前是标准件，现在是加工件
                    {
                      sql = "insert into dispatch_sheet (union_order, name, factory, ljmc, tzcc, czhi, zhl, rawdata, gjsl, material_no, cnc) values (\
                        '"+ order + "', '" + name + "', '" + factory + "', '" + cnc[j][3] + "', '" + cnc[j][4] + "', '" + cnc[j][5] + "',\
                        '"+ cnc[j][6] + "', '" + cnc[j][7] + "', '" + cnc[j][8] + "', '" + cnc[j][9] + "', '" + cnc[j][10] + "')";
                      let succ2 = await db_util.query(sql);
                      if (succ2.affectedRows == 0) {
                        console.log('插入小表失败', cnc[j]);
                      }
                    }
                    else {
                      sql = "update dispatch_sheet set name = '" + name + "', factory = '" + factory + "', tzcc = '" + cnc[j][4] + "',\
                            czhi = '"+ cnc[j][5] + "', zhl = '" + cnc[j][6] + "', gjsl = '" + cnc[j][8] + "',\
                            material_no = '"+ cnc[j][9] + "' where union_order = '" + order + "' and ljmc = '" + cnc[j][3] + "' and gjsl != '0'";
                      await db_util.query(sql);
                    }
                    break;
                  }
                }
              }
              else {
                if (succ3[j]['type_flag'] != data[k][14]) // 以前是加工件，现在是标准件，不在cnc里，从小表中删除吧
                {
                  sql = "update dispatch_sheet set gjsl = '0' where union_order = '" + order + "' and ljmc = '" + succ3[j].sheet_order + "'";
                  let succ5 = await db_util.query(sql);
                  if (succ5.affectedRows > 0)
                    console.log('把小表中旧记录清零', order, succ3[j]['sheet_order']);
                  else
                    console.log('小表中旧记录清零失败', sql);
                }
              }
              break;
            }
          }
          if (j == succ3.length) // 新增的记录
          {
            console.log('新增记录', data[k][0], data[k][1], data[k][2]);
            sql = "insert into machining_sheet (union_order, type, sheet_order, size_length, size_width, size_height, material_no, stuff, density, quatity, quatity_total, weight, bom_remark, stuff2, type_flag, status) values (\
                  '"+ data[k][0] + "', '" + data[k][1] + "', '" + data[k][2] + "', '" + data[k][3] + "', '" + data[k][4] + "', '" + data[k][5] + "',\
                  '"+ data[k][6] + "', '" + data[k][7] + "', '" + data[k][8] + "', '" + data[k][9] + "', '" + data[k][10] + "', '" + data[k][11] + "',\
                  '"+ data[k][12] + "', '" + data[k][13] + "', '" + data[k][14] + "', '" + data[k][15] + "')";
            await db_util.query(sql);
            if (data[k][14] == "1") // 加工件
            {
              for (j = 0; j < cnc.length; j++) {
                if (cnc[j][3] == data[k][2]) {
                  sql = "insert into dispatch_sheet (union_order, name, factory, ljmc, tzcc, czhi, zhl, rawdata, gjsl, material_no, cnc) values (\
                        '"+ order + "', '" + name + "', '" + factory + "', '" + cnc[j][3] + "', '" + cnc[j][4] + "', '" + cnc[j][5] + "',\
                        '"+ cnc[j][6] + "', '" + cnc[j][7] + "', '" + cnc[j][8] + "', '" + cnc[j][9] + "', '" + cnc[j][10] + "')";
                  await db_util.query(sql);
                  break;
                }
              }
            }
            gongjianzongshu++;
          }
        }
        if (temp.length < succ3.length) // 还存在旧记录在新表中没有，是否需要删除呢？
        {
          for (j = 0; j < succ3.length; j++) {
            for (k = 0; k < temp.length; k++) {
              if (temp[k] == succ3[j].id)
                break;
            }
            if (k == temp.length) {
              //sql = "delete from machining_sheet where id = '"+ succ3[j].id +"'";
              //console.log(sql);
              //sql = "delete from dispatch_sheet where union_order = '"+ order +"' and ljmc = '"+ succ3[j].sheet_order +"'";
              //console.log(sql);
              // 不删除，把数量设为0
              sql = "update machining_sheet set quatity = '0', quatity_total = '0' where id = '" + succ3[j].id + "'";
              let succ5 = await db_util.query(sql);
              if (succ5.affectedRows > 0)
                console.log('把大表中旧记录清零：', order, succ3[j]['sheet_order'], succ3[j]['type']);
              else
                console.log('Failed to', sql);
              if (succ3[j]['type_flag'] == 1) // 加工件
              {
                sql = "update dispatch_sheet set gjsl = '0' where union_order = '" + order + "' and ljmc = '" + succ3[j].sheet_order + "'";
                let succ5 = await db_util.query(sql);
                if (succ5.affectedRows > 0)
                  console.log('把小表中旧记录清零：', order, succ3[j]['sheet_order']);
                else
                  console.log('Failed to', sql);
              }
            }
          }
        }
        if (gongjianzongshu > 0) {
          if (jiagongjianshu > 0) {
            setTimeout(function () { ParsePdfFile(order, order, imageNo); }, 1000);
          }
          else {
            console.log(order + ' 没有加工件，直接进组装');
            sql = "update machining_union_sheet set stage = '0000010000' where union_order = '" + order + "'";
            await db_util.query(sql);
          }
          console.log('ParseBOMFile succeeded to update sheet table.');
        }
      }
    }
    return ret;
  }
  catch (error) {
    console.log('ParseBOMFile error: ' + error.message);
    console.log('SQL: ' + sql);
    /*if( order.length > 0 )
    {
      sql = "delete from machining_sheet where union_order = '" + order + "'";
      await db_util.query(sql);
      sql = "delete from machining_union_sheet where union_order = '" + order + "'";
      await db_util.query(sql);
    }*/
    return error.message;
  }
}

//FSMS
app.post('/ParseBOMFile', async (req, res) => {
  var bomFile = req.body.filepath;
  if (bomFile == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "filepath is not set" });
    return;
  }
  try {
    var result = "not support this function";
    if (req.body.tryagain == 'yes')
      result = await ParseBOMFile(bomFile);
    var json = {};
    if (result == 'ok') {
      json["result"] = "ok";
    }
    else {
      json["result"] = "error";
      json["description"] = result;
    }
    res.status(200);
    res.json(json);
  }
  catch (error) {
    console.log('ParseBOMFile failed, error: ' + error.message);
    var json = {};
    json["result"] = "error";
    json["description"] = error.message;
    res.status(200);
    res.json(json);
  }
})

//FSMS
app.post('/DesignSendout', async (req, res) => {
  if (req.body.unionorder == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "unionorder is not set" });
    return;
  }
  try {
    let ret = await ValidDesignFiles(req.body.unionorder);
    res.status(200);
    if (ret == '')
      res.json({ "result": "ok" });
    else
      res.json({ "result": "error", "description": ret });
  }
  catch (error) {
    console.log('DesignSendout failed, error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/AddCncInfo', async (req, res) => {
  let body = req.body;
  let sql = "select * from cnc where name = '" + body.name + "' OR MachineName = '" + body.MachineName + "' OR MachineSN = '" + body.MachineSN + "'";
  try {
    let rows = await db_util.query(sql);
    if (rows.length > 0) {
      res.status(200);
      res.json({ "result": "error", "description": "名称或设备名称或设备序列号已存在" });
      return;
    }
    sql = "insert into cnc (name, MachineName, MachineModel, MachineSN) values('" + body.name + "', '" + body.MachineName + "', '" + body.MachineModel + "', '" + body.MachineSN + "')";
    let sucData = await db_util.query(sql);
    if (sucData.affectedRows > 0) {
      let json = {};
      json["id"] = sucData.insertId;
      json["name"] = body.name;
      json["diameter_max"] = 0;
      json["length_max"] = 0;
      json["width_max"] = 0;
      json["stuff_type"] = "";
      json["stuff_range"] = "";
      json["remark"] = "";
      json["loading"] = 0;
      json["reserved1"] = "";
      json["reserved2"] = "";
      json["MachineName"] = body.MachineName;
      json["MachineModel"] = body.MachineModel;
      json["MachineSN"] = body.MachineSN;
      json["lastmode"] = "";
      json["lastmode_starttime"] = "";
      json["lastmode_lasttime"] = "";
      g_cncInfo.push(json);
    }
    let date = new Date();
    await ResetCncMonthData(date);

    res.status(200);
    if (sucData.affectedRows > 0)
      res.json({ "result": "ok" });
    else
      res.json({ "result": "error" });
    console.log("AddCncInfo return id = " + sucData.insertId);
  }
  catch (error) {
    console.log('Failed to AddCncInfo: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/UpdateCncInfo', function (req, res) {
  var body = req.body;
  var flag = false;
  var sql = "Update cnc set ";
  var where = "";
  if (body.id == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "the id is not found" });
    return;
  }
  else {
    where = " where id = '" + body.id + "'";
  }
  if (body.name != undefined) {
    for (var i = 0; i < g_cncInfo.length; i++) {
      if (g_cncInfo[i].id == body.id)
        continue;
      if (g_cncInfo[i].name == body.name) {
        res.status(200);
        res.json({ "result": "error", "description": "名称已存在" });
        return;
      }
    }
    if (flag)
      sql += ", ";
    sql += "name = '" + body.name + "'";
    flag = true;
  }
  if (body.diameter_max != undefined) {
    if (flag)
      sql += ", ";
    sql += "diameter_max = '" + body.diameter_max + "'";
    flag = true;
  }
  if (body.length_max != undefined) {
    if (flag)
      sql += ", ";
    sql += "length_max = '" + body.length_max + "'";
    flag = true;
  }
  if (body.width_max != undefined) {
    if (flag)
      sql += ", ";
    sql += "width_max = '" + body.width_max + "'";
    flag = true;
  }
  if (body.stuff_type != undefined) {
    if (flag)
      sql += ", ";
    sql += "stuff_type = '" + body.stuff_type + "'";
    flag = true;
  }
  if (body.stuff_range != undefined) {
    if (flag)
      sql += ", ";
    sql += "stuff_range = '" + body.stuff_range + "'";
    flag = true;
  }
  if (body.remark != undefined) {
    if (flag)
      sql += ", ";
    sql += "remark = '" + body.remark + "'";
    flag = true;
  }
  if (body.MachineName != undefined) {
    for (var i = 0; i < g_cncInfo.length; i++) {
      if (g_cncInfo[i].id == body.id)
        continue;
      if (g_cncInfo[i].MachineName == body.MachineName) {
        res.status(200);
        res.json({ "result": "error", "description": "设备名称已存在" });
        return;
      }
    }
    if (flag)
      sql += ", ";
    sql += "MachineName = '" + body.MachineName + "'";
    flag = true;
  }
  if (body.MachineModel != undefined) {
    if (flag)
      sql += ", ";
    sql += "MachineModel = '" + body.MachineModel + "'";
    flag = true;
  }
  if (body.MachineSN != undefined) {
    for (var i = 0; i < g_cncInfo.length; i++) {
      if (g_cncInfo[i].id == body.id)
        continue;
      if (g_cncInfo[i].MachineSN == body.MachineSN) {
        res.status(200);
        res.json({ "result": "error", "description": "设备序列号已存在" });
        return;
      }
    }
    if (flag)
      sql += ", ";
    sql += "MachineSN = '" + body.MachineSN + "'";
    flag = true;
  }
  if (body.MachineNO != undefined) {
    if (flag)
      sql += ", ";
    sql += "MachineNO = '" + body.MachineNO + "'";
    flag = true;
  }
  if (body.guid != undefined) {
    if (flag)
      sql += ", ";
    sql += "guid = '" + body.guid + "'";
    flag = true;
  }
  if (body.Plant != undefined) {
    if (flag)
      sql += ", ";
    sql += "Plant = '" + body.Plant + "'";
    flag = true;
  }
  if (body.Dept != undefined) {
    if (flag)
      sql += ", ";
    sql += "Dept = '" + body.Dept + "'";
    flag = true;
  }
  if (flag) {
    sql += where;
    //console.log(sql);
    db_util.ExecuteSQL(sql, null,
      (sucData) => {
        for (var i = 0; i < g_cncInfo.length; i++) {
          if (g_cncInfo[i].id == body.id) {
            if (body.name != undefined)
              g_cncInfo[i].name = body.name;
            if (body.diameter_max != undefined)
              g_cncInfo[i].diameter_max = body.diameter_max;
            if (body.length_max != undefined)
              g_cncInfo[i].length_max = body.length_max;
            if (body.width_max != undefined)
              g_cncInfo[i].width_max = body.width_max;
            if (body.stuff_type != undefined)
              g_cncInfo[i].stuff_type = body.stuff_type;
            if (body.stuff_range != undefined)
              g_cncInfo[i].stuff_range = body.stuff_range;
            if (body.remark != undefined)
              g_cncInfo[i].remark = body.remark;
            if (body.MachineName != undefined)
              g_cncInfo[i].MachineName = body.MachineName;
            if (body.MachineModel != undefined)
              g_cncInfo[i].MachineModel = body.MachineModel;
            if (body.MachineSN != undefined)
              g_cncInfo[i].MachineSN = body.MachineSN;
            if (body.MachineNO != undefined)
              g_cncInfo[i].MachineNO = body.MachineNO;
            if (body.guid != undefined)
              g_cncInfo[i].guid = body.guid;
            if (body.Plant != undefined)
              g_cncInfo[i].Plant = body.Plant;
            if (body.Dept != undefined)
              g_cncInfo[i].Dept = body.Dept;
            break;
          }
        }
        console.log(sucData.message);
        res.status(200);
        if (sucData.affectedRows > 0)
          res.json({ "result": "ok", "changedRows": sucData.changedRows });
        else
          res.json({ "result": "error", "description": "not find the record" });
      },
      (errData) => {
        res.status(200);
        res.json({ "result": "error", "description": errData.message });
        console.log('Failed: ' + sql);
      }
    );
  }
  else {
    res.status(200);
    res.json({ "result": "error", "description": "no column was matched to update" });
    console.log('Failed, no column was matched to update');
  }
})

//FSMS
app.post('/DeleteCncInfo', async (req, res) => {
  if (req.body.id == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set parameter of id" });
    return;
  }
  let sql = "delete from cnc where id = '" + req.body.id + "'";
  try {
    let result = await db_util.query(sql);
    if (result.affectedRows > 0) {
      for (let i = 0; i < g_cncInfo.length; i++) {
        if (g_cncInfo[i].id == req.body.id) {
          g_cncInfo.splice(i, 1);
          break;
        }
      }
    }
    let date = new Date();
    await ResetCncMonthData(date);

    res.status(200);
    if (result.affectedRows > 0)
      res.json({ "result": "ok" });
    else
      res.json({ "result": "error", "description": "no row data matched the id" });
  }
  catch (error) {
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryCncData', async (req, res) => {
  let body = req.body;
  let sql = "select * from dispatch_sheet";
  let cnc = "";
  if (body.cnc != undefined) {
    if (body.cnc.length > 0 && body.cnc != "所有機台") {
      cnc = body.cnc;
    }
  }
  if (cnc.length == 0) {
    if (body.unionorder == undefined) {
    }
    else if (body.unionorder.length > 0) {
      sql += " where union_order = '" + body.unionorder + "'";
      if (body.sheetorder != undefined)
        sql += " and ljmc = '" + body.sheetorder + "'";
    }
  }
  else {
    if (body.unionorder == undefined) {
      if (cnc.length > 0)
        sql += " where cnc like '%" + cnc + "%'"
    }
    else {
      if (body.unionorder.length > 0) {
        if (cnc.length > 0)
          sql += " where union_order = '" + body.unionorder + "' and cnc like '%" + cnc + "%'";
        else
          sql += " where union_order = '" + body.unionorder + "'";
      }
      else if (cnc.length > 0) {
        sql += " where cnc like '%" + cnc + "%'"
      }
    }
  }
  if (body.box != undefined) {
    if (body.box.length > 0) {
      if (sql.indexOf('where') > 0)
        sql += " and box like '%" + body.box + "%'";
      else
        sql += " where box like '%" + body.box + "%'";
    }
  }
  if (body.flag != undefined) // 不需要rawdata为0的记录
  {
    if (sql.indexOf('where') > 0)
      sql += " and rawdata != 0";
    else
      sql += " where rawdata != 0";
  }
  let status = -1;
  if (body.status != undefined) {
    status = parseInt(body.status);
    if (isNaN(status))
      status = -1;
  }
  if (status >= 0) {
    if (sql.indexOf('where') > 0)
      sql += " and status = '" + status + "'";
    else
      sql += " where status = '" + status + "'";
  }
  if (body.order != undefined) {
    sql += " " + body.order + "";
  }
  else {
    sql += " ORDER BY ljmc ASC";
  }
  console.log('QueryCncData', body, sql);
  try {
    let flag = false;
    let sucData = await db_util.query(sql);
    let array = new Array();
    let riqi = "";
    if (body.riqi != undefined) {
      let date = new Date();
      let tempTime = Date.parse(body.riqi);
      if (isNaN(tempTime) == false) {
        date.setTime(tempTime);
        riqi = getMonthDayTime(date, 1);
      }
    }
    let last_time = Date.now();
    sql = "select id, Time from cncdata ORDER BY id desc LIMIT 1";
    let succ3 = await db_util.query(sql);
    if (succ3.length > 0)
      last_time = parseInt(succ3[0]['Time']);

    for (let k = 0; k < sucData.length; k++) // 小表数据
    {
      flag = false;
      if (body.banci == undefined || body.banci == '') {
        flag = true;
      }
      else {
        // 取消了编程 - 2021/02/19
        /*if( status == 1 ) // 编程
        {
          if( body.banci == suc[i].banci2 )
          {
            flag = true;
          }
        }
        else */
        if (status == 1 || status == 2) // 加工
        {
          if (body.banci == sucData[k].banci) {
            flag = true;
          }
        }
        else {
          flag = true;
        }
      }
      if (flag && riqi != '') {
        if (sucData[k].jiagongriqi.indexOf(riqi) < 0)
          flag = false;
      }
      if (flag) {
        let time = Date.now() - 28 * 24 * 3600 * 1000;
        if (time < last_time && sucData[k]["cxmc"] != '' && sucData[k].cnc != '') {
          let MachineName = "";
          for (let j = 0; j < g_cncInfo.length; j++) {
            if (g_cncInfo[j].name == sucData[k].cnc) {
              MachineName = g_cncInfo[j].MachineName;
              break;
            }
          }
          sql = "select id, evt_type, Time from cncdata where MachineName = '" + MachineName + "' and program = '" + sucData[k]["cxmc"] + "' and Time > '" + time + "' ORDER BY id DESC";
          let suc2 = await db_util.query(sql);
          let pcsID = 0; // 结束标志
          let runID = 0; // 开始标志。由于是倒序排列，runID应该大于pcsID
          for (let j = 0; j < suc2.length; j++) {
            if (suc2[j].evt_type == 'Pcs') {
              pcsID = j;
              break;
            }
          }
          for (let j = suc2.length - 1; j > 0; j--) {
            if (suc2[j].evt_type == 'Run') {
              runID = j;
              break;
            }
          }
          if (runID > 0) {
            if (pcsID == 0 || pcsID > runID) // 还没有完成加工，或者Pcs在Run之前出现
            {
              pcsID = parseInt(suc2[0].Time) - parseInt(suc2[runID].Time);
              sucData[k]["cncsj"] = pcsID / 1000;
            }
            else if (sucData[k].cncsj == '') {
              let starttime = parseInt(suc2[runID].Time);
              let endtime = parseInt(suc2[pcsID].Time);
              sucData[k].cncsj = (endtime - starttime) / 60000; // 单位为分钟
            }
          }
        }
        sucData[k].cncsj = dotFixed(sucData[k].cncsj);
        sql = "select * from machining_sheet where quatity != '0' and union_order = '" + sucData[k].union_order + "' and sheet_order = '" + sucData[k].ljmc + "'";
        let suc = await db_util.query(sql);
        if (suc.length > 0) {
          sucData[k]["imagefile"] = suc[0].imagefile;
          if (suc[0].bom_remark != 'V')
            sucData[k]["bom_remark"] = "";
          else
            sucData[k]["bom_remark"] = suc[0].bom_remark;
        }
        else {
          sucData[k]["imagefile"] = "";
          sucData[k]["bom_remark"] = "";
        }
        array.push(sucData[k]);
      }
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryCncData exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

// 根据传入的工单号的stage以及工件的status查询工单及工件  FSMS
app.post('/QueryCncDataEx', async (req, res) => {
  let body = req.body;
  if (body.stage == undefined || body.status == undefined) {
    console.log('QueryCncDataEx error: stage or status undefined');
    res.status(200);
    res.json({ "result": "error", "description": "stage or status undefined" });
    return;
  }
  let sql = "select union_order from machining_union_sheet where status = 0";
  if (body.stage.length > 1) {
    sql += " and stage = '" + body.stage + "'";
  }
  else {
    let count = parseInt(body.stage);
    if (count > 0) {
      sql += " and stage like '";
      for (let i = 0; i < count; i++) {
        sql += "_";
      }
      sql += "1%'";
    }
    else {
      sql += " and stage like '1%'";
    }
  }
  console.log('QueryCncDataEx', body, sql);
  try {
    let array = new Array();
    let suc = await db_util.query(sql);
    for (let i = 0; i < suc.length; i++) {
      sql = "select id, ljmc, gjsl from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and status = '" + body.status + "'";
      let suc2 = await db_util.query(sql);
      for (let k = 0; k < suc2.length; k++) {
        let json = {};
        json["unionorder"] = suc[i].union_order;
        json["workorder"] = suc2[k].ljmc;
        json["id"] = suc2[k].id;
        json["gjsl"] = suc2[k].gjsl;
        array.push(json);
      }
    }
    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryCncDataEx exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryCncDataByID', async (req, res) => {
  console.log('QueryCncDataByID', req.body);
  try {
    let array = new Array();
    let sql = "select * from dispatch_sheet where id = '" + req.body.id + "'";
    let suc = await db_util.query(sql);
    for (let i = 0; i < suc.length; i++) {
      array.push(suc[i]);
    }
    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryCncDataByID exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

// 根据传入的工单号和工件号查询该工件的分单状态 FSMS
app.post('/QueryCncDataSubOrder', async (req, res) => {
  let body = req.body;
  let sql = "select * from dispatch_sheet where gjsl != '0' and rawdata != 0";
  if (body.unionorder != undefined && body.unionorder != '')
    sql += " and union_order = '" + body.unionorder + "'";
  if (body.workorder != undefined && body.workorder != '')
    sql += " and ljmc = '" + body.workorder + "'";
  if (body.status != undefined)
    sql += " and status = '" + body.status + "'";
  try {
    console.log('QueryCncDataSubOrder', body, sql);
    let array = new Array();
    let suc = await db_util.query(sql);
    for (let i = 0; i < suc.length; i++) {
      suc[i]["unionorder"] = suc[i].union_order;
      suc[i]["workorder"] = suc[i].ljmc;
      suc[i]["sheet_order"] = suc[i].ljmc;
      suc[i]["cnc_name"] = suc[i].cnc;
      if (suc[i].rawdata == 2)
        suc[i]["chaidan"] = 1;
      else
        suc[i]["chaidan"] = 0;
      suc[i]["bom_remark"] = "";
      sql = "select bom_remark from machining_sheet where quatity != '0' and union_order = '" + suc[i].union_order + "' and sheet_order = '" + suc[i].ljmc + "'";
      let succ2 = await db_util.query(sql);
      if (succ2.length > 0) {
        if (succ2[0].bom_remark != 'V')
          suc[i]["bom_remark"] = "";
        else
          suc[i]["bom_remark"] = succ2[0].bom_remark;
      }
      array.push(suc[i]);
    }
    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryCncDataSubOrder exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

// 编程时批量指派CNC机台；二次加工时批量指派工程师 FSMS
app.post('/UpdateCncDataEx', async (req, res) => {
  let body = req.body;
  if (body.status != '1' && body.status != '4') {
    console.log('UpdateCncDataEx error: 必须指定status为1（编程）或4（二次加工）');
    res.status(200);
    res.json({ "result": "error", "description": "必须指定status为1（编程）或4（二次加工）" });
    return;
  }
  try {
    let sql = "";
    if (body.status == '1') // 编程
    {
      let cnc = body.cnc;
      if (body.cnc == undefined)
        cnc = body.cnc_name;
      for (let i = 0; i < body.list.length; i++) {
        if (cnc != undefined)
          sql = "update dispatch_sheet set cnc = '" + cnc + "', banci = '" + body.banci + "', jiagongriqi = '" + body.jiagongriqi + "', end_date = '" + body.end_date + "', estimate_time = '" + body.estimate_time + "' where id = '" + body.list[i].id + "'";
        else
          sql = "update dispatch_sheet set banci = '" + body.banci + "', jiagongriqi = '" + body.jiagongriqi + "', end_date = '" + body.end_date + "', estimate_time = '" + body.estimate_time + "' where id = '" + body.list[i].id + "'";
        console.log('批量指派：' + sql);
        await db_util.query(sql);
      }
    }
    else // 二次加工
    {
      let engineer = "";
      for (let i = 0; i < body.engineer_ercijiagong.length; i++) {
        if (i > 0)
          engineer += ",";
        engineer += body.engineer_ercijiagong[i];
      }
      for (let i = 0; i < body.list.length; i++) {
        sql = "update dispatch_sheet set machine_end_date_2 = '" + body.machine_end_date_2 + "', machine_time_2 = '" + body.machine_time_2 + "', engineer_ercijiagong = '" + engineer + "' where id = '" + body.list[i].id + "'";
        console.log('二次加工批量指派：' + sql);
        await db_util.query(sql);

        sql = "delete from machining_engineer where union_order = '" + body.list[i].unionorder + "' and sheet_order = '" + body.list[i].workorder + "' and type = 'engineer_ercijiagong'";
        await db_util.query(sql);
        let suc2 = await db_util.query("select name, job_no from employee");
        var engineers = new Array();
        for (let k = 0; k < body.engineer_ercijiagong.length; k++) {
          let temp = new Array(5);
          temp[0] = body.list[i].unionorder;
          temp[1] = body.list[i].workorder;
          temp[2] = "";
          temp[3] = body.engineer_ercijiagong[k];
          temp[4] = "engineer_ercijiagong";
          for (let n = 0; n < suc2.length; n++) {
            if (suc2[n].name == body.engineer_ercijiagong[k]) {
              temp[2] = suc2[n].job_no;
              break;
            }
          }
          engineers.push(temp);
        }
        if (engineers.length > 0) {
          sql = "insert into machining_engineer values ?";
          await db_util.query(sql, [engineers]);
        }
      }
    }

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('UpdateCncDataEx exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/AddCncData', async (req, res) => {
  let body = req.body;
  let col = "";
  let val = "";
  let id = 0;
  let quatity = 0;
  let count = 0;
  if (body.unionorder == undefined || body.name == undefined || body.factory == undefined || body.ljmc == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "unionorder or name or factory or ljmc is not found" });
    return;
  }
  if (body.unionorder == '' || body.ljmc == '' || body.factory == '' || body.ljmc == '') {
    console.log('AddCncData 传入的参数：unionorder or name or factory or ljmc 不可以为空。');
    res.status(200);
    res.json({ "result": "error", "description": "unionorder or name or factory or ljmc 不可以为空。" });
    return;
  }
  if (body.chaidan != undefined) {
    count = parseInt(body.chaidan);
    if (isNaN(count))
      count = 0;
    let sql = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + body.unionorder + "' and ljmc = '" + body.ljmc + "' and rawdata = 1";
    let suc2 = await db_util.query(sql);
    if (suc2.length > 0) {
      id = suc2[0].id;
      quatity = parseInt(suc2[0].gjsl);
    }
    if (count == 0 || (count + 1) >= quatity) {
      res.status(200);
      res.json({ "result": "error", "description": "工件数量不足。" });
      return;
    }
  }
  try {
    let sql = "select column_name from information_schema.COLUMNS where table_schema = '" + db_util.config.db_name + "' and table_name = 'dispatch_sheet' ORDER BY ordinal_position ASC";
    let suc3 = await db_util.query(sql);
    for (let i = 1; i < suc3.length; i++) // 去掉id
    {
      if (suc3[i].column_name == 'rawdata') {
        col += ",";
        col += suc3[i].column_name;
        if (id == 0)
          val += ",0";
        else
          val += ",2";
      }
      else if (suc3[i].column_name == 'union_order') {
        if (col != '') {
          col += ",";
          val += ",";
        }
        col += suc3[i].column_name;
        val += '\'';
        val += body["unionorder"];
        val += '\'';
      }
      else if (suc3[i].column_name == 'gjsl') {
        if (col != '') {
          col += ",";
          val += ",";
        }
        col += suc3[i].column_name;
        val += '\'';
        if (id == 0)
          val += body[suc3[i].column_name];
        else
          val += count;
        val += '\'';
      }
      else if (body[suc3[i].column_name] != undefined) {
        if (col != '') {
          col += ",";
          val += ",";
        }
        col += suc3[i].column_name;
        val += '\'';
        val += body[suc3[i].column_name];
        val += '\'';
      }
    }
    sql = "insert into dispatch_sheet (" + col + ") values (" + val + ")";
    //console.log(sql);
    let suc = await db_util.query(sql);
    if (id > 0) {
      quatity -= count;
      sql = "Update dispatch_sheet set gjsl = '" + quatity + "' where id = '" + id + "'";
      await db_util.query(sql);
      console.log(sql);
    }

    res.status(200);
    res.json({ "result": "ok", "id": suc.insertId });
    console.log("AddCncData return id = " + suc.insertId);
  }
  catch (error) {
    console.log('AddCncData exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/AddCncDataEx', async (req, res) => {
  let body = req.body;
  let col = "";
  let val = "";
  if (body.id == undefined || body.gjsl == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "id or gjsl is not found" });
    return;
  }
  let gjsl2 = parseFloat(body.gjsl);
  if (isNaN(gjsl2)) {
    res.status(200);
    res.json({ "result": "error", "description": "gjsl is invalid" });
    return;
  }

  try {
    let sql = "select * from dispatch_sheet where id = '" + body.id + "'";
    let suc2 = await db_util.query(sql);
    if (suc2.length == 0) {
      res.status(200);
      res.json({ "result": "error", "description": "id not exist" });
      return;
    }
    /*if( suc2[0].rawdata == '0' )
    {
      res.status(200);
      res.json({"result":"error", "description":"item is not raw data"});
      return;
    }*/
    let gjsl = parseFloat(suc2[0].gjsl);
    if (isNaN(gjsl)) {
      res.status(200);
      res.json({ "result": "error", "description": "gjsl is null in table" });
      return;
    }
    if (gjsl <= gjsl2) {
      res.status(200);
      res.json({ "result": "error", "description": "拆单量太大了" });
      return;
    }
    sql = "select column_name from information_schema.COLUMNS where table_schema = '" + db_util.config.db_name + "' and table_name = 'dispatch_sheet' ORDER BY ordinal_position ASC";
    let suc3 = await db_util.query(sql);
    for (let i = 1; i < suc3.length; i++) // 去掉id
    {
      if (i > 1) {
        col += ",";
        val += ",";
      }
      col += suc3[i].column_name;
      val += '\'';
      if (suc3[i].column_name == 'cnc') {
        if (body.cnc != undefined) {
          val += body.cnc;
        }
        else {
          val += suc2[0][suc3[i].column_name]
        }
      }
      else if (suc3[i].column_name == 'box') {
        if (body.box != undefined) {
          val += body.box;
        }
        else {
          val += suc2[0][suc3[i].column_name]
        }
      }
      else if (suc3[i].column_name == 'gjsl') {
        val += body.gjsl;
      }
      else if (suc3[i].column_name == 'rawdata') {
        val += "2";
      }
      else if (suc3[i].column_name == 'jiagongriqi') {
        if (body.jiagongriqi != undefined) {
          val += body.jiagongriqi;
        }
        else {
          val += suc2[0][suc3[i].column_name]
        }
      }
      else if (suc3[i].column_name == 'banci') {
        if (body.banci != undefined) {
          val += body.banci;
        }
        else {
          val += suc2[0][suc3[i].column_name]
        }
      }
      else if (suc3[i].column_name == 'parentID') {
        val += body.id;
      }
      else {
        val += suc2[0][suc3[i].column_name]
      }
      val += '\'';
    }
    sql = "insert into dispatch_sheet (" + col + ") values (" + val + ")";
    //console.log(sql);
    let suc = await db_util.query(sql);

    gjsl -= gjsl2;
    sql = "update dispatch_sheet set gjsl = '" + gjsl + "' where id = '" + body.id + "'";
    await db_util.query(sql);
    console.log(sql);

    res.status(200);
    res.json({ "result": "ok", "id": suc.insertId });
    console.log("AddCncDataEx 拆单成功，return id = " + suc.insertId);
  }
  catch (error) {
    console.log('AddCncDataEx exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/UpdateCncData', async (req, res) => {
  let body = req.body;
  let flag = false;
  let where = "";
  //console.log('UpdateCncData', body);
  if (body.id == undefined) {
    if (body.unionorder == undefined || body.workorder == undefined) {
      res.status(200);
      res.json({ "result": "error", "description": "the id or unionorder/workorder is not found" });
      return;
    }
    where = " where union_order = '" + body.unionorder + "' and ljmc = '" + body.workorder + "' and gjsl != '0'";
  }
  else {
    where = " where id = '" + body.id + "'";
  }
  try {
    let sql = "select column_name from information_schema.COLUMNS where table_schema = '" + db_util.config.db_name + "' and table_name = 'dispatch_sheet' ORDER BY ordinal_position ASC";
    let suc3 = await db_util.query(sql);
    sql = "Update dispatch_sheet set ";
    for (let i = 5; i < suc3.length; i++) // 去掉id、union_order、name、factory、ljmc
    {
      if (suc3[i].column_name == 'rawdata')
        continue;
      else if (suc3[i].column_name == 'parentID')
        continue;
      if (body[suc3[i].column_name] == undefined)
        continue;
      if (flag)
        sql += ", ";
      sql += suc3[i].column_name;
      sql += " = \'";
      if (suc3[i].column_name == 'engineer_ercijiagong') {
        let temp = "";
        for (let k = 0; k < body.engineer_ercijiagong.length; k++) {
          if (k > 0)
            temp += ",";
          temp += body.engineer_ercijiagong[k];
        }
        sql += temp;
      }
      else {
        sql += body[suc3[i].column_name];
      }
      sql += '\'';
      flag = true;
    }

    if (flag == false) {
      console.log('UpdateCncData error: no column to update');
      res.status(200);
      res.json({ "result": "error", "description": "no column to update" });
      return;
    }
    sql += where;
    //console.log(sql);
    let suc = await db_util.query(sql);
    if (suc.affectedRows == 0) {
      console.log('Failed to execute: ' + sql);
      if (body["box"] != undefined) // 修改箱号，可能是标准件，在大表中
      {
        if (body["leo"] == '1') // 解锁箱号，传入的箱号为空，只解同一箱号的标准件
        {
          sql = "select id, box from machining_sheet where quatity != '0' and union_order = '" + body.unionorder + "' and sheet_order = '" + body.workorder + "'";
          let succ2 = await db_util.query(sql);
          if (succ2.length > 0) {
            sql = "Update machining_sheet set box = '" + body["box"] + "' where quatity != '0' and union_order = '" + body.unionorder + "' and type_flag = 0 and box = '" + succ2[0]["box"] + "'";
            suc = await db_util.query(sql);
            if (suc.affectedRows == 0)
              console.log('Failed to execute: ' + sql);
            else
              console.log('修改标准件箱号，' + sql);
          }
          else {
            console.log('Not find any item: ' + sql);
          }
        }
        else {
          sql = "Update machining_sheet set box = '" + body["box"] + "' where quatity != '0' and union_order = '" + body.unionorder + "' and sheet_order = '" + body.workorder + "'";
          suc = await db_util.query(sql);
          if (suc.affectedRows == 0)
            console.log('Failed to execute: ' + sql);
          else
            console.log('修改标准件箱号，' + sql);
        }
      }
    }

    res.status(200);
    if (suc.affectedRows > 0)
      res.json({ "result": "ok", "changedRows": suc.changedRows });
    else
      res.json({ "result": "error", "description": "not find the record" });
  }
  catch (error) {
    console.log('UpdateCncData exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//NOUSE
app.post('/RejectCncData', async (req, res) => {
  let body = req.body;
  if (body.id == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "id is not set" });
    return;
  }
  try {
    let sql = "select * from dispatch_sheet where id = '" + body.id + "'";
    let suc = await db_util.query(sql);
    console.log('排工单退单：' + body.id + ' - ' + suc[0].union_order + ' - ' + suc[0].ljmc);
    sql = "update dispatch_sheet set remark = '" + body.remark + "' where id = '" + body.id + "'";
    await db_util.query(sql);

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('RejectCncData exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/DeleteCncData', async (req, res) => {
  let sql = "select * from dispatch_sheet where id = '" + req.body.id + "'";
  try {
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      res.status(200);
      res.json({ "result": "error", "description": "not find matched id" });
      return;
    }
    if (suc[0].rawdata == 1) // 非原始数据才可以删除
    {
      console.log('dispatch_sheet id = ' + req.body.id + ', 原始数据不可以删除');
      res.status(200);
      res.json({ "result": "error", "description": "该条记录不可以删除" });
      return;
    }
    sql = "delete from dispatch_sheet where id = '" + req.body.id + "'";
    await db_util.query(sql);
    console.log(sql);
    if (suc[0].rawdata == 2) {
      let gjsl = parseInt(suc[0].gjsl);
      sql = "select * from dispatch_sheet where id = '" + suc[0].parentID + "'";
      let suc2 = await db_util.query(sql);
      if (suc2.length > 0) {
        if (suc2[0].status == '1' || suc2[0].status == '2') {
          gjsl += parseInt(suc2[0].gjsl);
          sql = "update dispatch_sheet set gjsl = '" + gjsl + "' where id = " + suc2[0].id + "";
          await db_util.query(sql);
          console.log(sql);
        }
        else {
          console.log('DeleteCncData: ' + sql + ', 状态不在编程或加工，不能更新加工数量。');
        }
      }
      else {
        sql = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + suc[0].union_order + "' and ljmc = '" + suc[0].ljmc + "' and rawdata != 0";
        let suc2 = await db_util.query(sql);
        if (suc2.length > 0) {
          if (suc2[0].status == '1' || suc2[0].status == '2') {
            gjsl += parseInt(suc2[0].gjsl);
            sql = "update dispatch_sheet set gjsl = '" + gjsl + "' where id = " + suc2[0].id + "";
            await db_util.query(sql);
            console.log(sql);
          }
          else {
            console.log('DeleteCncData: ' + sql + ', 状态不在编程或加工，不能更新加工数量。');
          }
        }
        else {
          console.log('DeleteCncData: ' + sql + ', 查询没有找到记录。');
        }
      }
      sql = "select * from dispatch_sheet where gjsl != '0' and parentID = '" + req.body.id + "'";
      let succ3 = await db_util.query(sql);
      if (succ3.length > 0) {
        sql = "update dispatch_sheet set parentID = '" + suc[0].parentID + "' where parentID = '" + req.body.id + "'";
        await db_util.query(sql);
        console.log('DeleteCncData: ' + sql);
      }
    }

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('DeleteCncData exception: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//NOUSE
app.post('/QueryCncAdjustTime', function (req, res) {
  var sql = "select * from cnctime";
  db_util.ExecuteSQL(sql, null,
    (sucData) => {
      var json = {};
      var array = new Array();
      if (sucData.length > 0) {
        sucData.forEach(element => {
          array.push(element);
        });
      }
      json["result"] = "ok";
      json["order"] = array;
      res.status(200);
      res.json(json);
      console.log('query cncAdjustTime data: ' + array.length);
    },
    (errData) => {
      console.log(errData.message);
      res.status(200);
      json["result"] = "error";
      json["errorCode"] = "1";
      json["description"] = errData.message;
      res.json(json);
    }
  );
})

//NOUSE
app.post('/AddCncAdjustTime', async (req, res) => {
  let body = req.body;
  if (body.starttime == undefined || body.starttime == 'null' || body.endtime == undefined || body.endtime == 'null') {
    res.status(200);
    res.json({ "result": "error", "description": "starttime or endtime not set" });
    return;
  }
  let start = parseInt(body.starttime);
  let end = parseInt(body.endtime);
  if (start > end) {
    start = end;
    end = parseInt(body.starttime);
  }
  let sql = "select * from cnctime";
  try {
    let suc = await db_util.query(sql);
    for (let i = 0; i < suc.length; i++) {
      let st = parseInt(suc[i].starttime);
      let et = parseInt(suc[i].endtime);
      if (start >= et || end <= st)
        continue;
      console.log('设备生产时间设置有冲突，新的时间段：' + body.starttime + ' ~ ' + body.endtime + '，冲突时间段：' + suc[i].starttime + ' ~ ' + suc[i].endtime);
      res.status(200);
      res.json({ "result": "error" });
      return;
    }
    sql = "select * from information_schema.columns where table_name = 'cnctime' and column_name = 'reserved'";
    let suc2 = await db_util.query(sql);
    if (suc2.length == 0) {
      sql = "insert into cnctime values(null, '" + body.starttime + "', '" + body.endtime + "', '" + body.status + "', '" + body.hours + "')";
    }
    else {
      let date = new Date(start);
      let dt = getMonthDayTime(date, 1, 1);
      dt += " from ";
      dt += req.ip;
      sql = "insert into cnctime values(null, '" + body.starttime + "', '" + body.endtime + "', '" + body.status + "', '" + body.hours + "', '" + dt + "')";
    }
    let sucData = await db_util.query(sql);
    if (sucData.affectedRows > 0) {
      let date = new Date();
      let currentTime = date.getTime();
      setTime(date, 0, 0, 0, 0);
      date.setDate(1);
      if (start < currentTime && end > date.getTime()) {
        console.log("AddCncAdjustTime 清空表中数据");
        await ResetCncMonthData(date);
      }
    }
    res.status(200);
    if (sucData.affectedRows > 0)
      res.json({ "result": "ok" });
    else
      res.json({ "result": "error" });
    console.log("AddCncAdjustTime return id = " + sucData.insertId);
  }
  catch (error) {
    console.log('Failed to AddCncAdjustTime: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//NOUSE
app.post('/UpdateCncAdjustTime', async (req, res) => {
  let body = req.body;
  try {
    let sql = "select * from cnctime where id = '" + body.id + "'";
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      res.status(200);
      res.json({ "result": "error", "description": "not find the id" });
      return;
    }
    sql = "select * from information_schema.columns where table_name = 'cnctime' and column_name = 'reserved'";
    let suc2 = await db_util.query(sql);
    if (suc2.length == 0) {
      sql = "update cnctime set starttime = '" + body.starttime + "', endtime = '" + body.endtime + "', status = '" + body.status + "', hours = '" + body.hours + "' where id = '" + body.id + "'";
    }
    else {
      let date = new Date();
      let dt = suc[0].reserved + "; updated by " + req.ip + " on " + getMonthDayTime(date, 1, 1);
      sql = "update cnctime set starttime = '" + body.starttime + "', endtime = '" + body.endtime + "', status = '" + body.status + "', hours = '" + body.hours + "', reserved = '" + dt + "' where id = '" + body.id + "'";
    }
    console.log(sql);
    await db_util.query(sql);
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('Failed to UpdateCncAdjustTime: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//NOUSE
app.post('/DeleteCncAdjustTime', async (req, res) => {
  try {
    let sql = "select * from cnctime where id = '" + req.body.id + "'";
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      res.status(200);
      res.json({ "result": "error", "description": "not find the id" });
      return;
    }
    sql = "delete from cnctime where id = '" + req.body.id + "'";
    await db_util.query(sql);
    let date = new Date();
    let endtime = getMonthDayTime(date, 1, 1);
    date.setTime(parseInt(suc[0].starttime));
    let starttime = getMonthDayTime(date, 1, 1);
    let temp = "id=" + suc[0].id + " starttime=" + starttime + " status=" + suc[0].status + " hours=" + suc[0].hours + " was delete by " + req.ip + " on " + endtime;
    sql = "insert into cncother(name, value) values('cnctime', '" + temp + "')";
    await db_util.query(sql);

    if (date.getTime() < Date.now()) {
      let succ2 = await db_util.query("select id, Time from cncdata limit 1");
      if (succ2.length == 0) {
        res.status(200);
        res.json({ "result": "ok" });
        return;
      }
      let i = parseInt(suc[0].endtime);
      let k = parseInt(succ2[0]['Time']);
      if (i <= k) {
        res.status(200);
        res.json({ "result": "ok" });
        return;
      }
      k = parseInt(suc[0].starttime);
      date.setTime(Date.now());
      date.setDate(1);
      setTime(date, 0);
      if (k >= date.getTime()) // 当前月
      {
        await ResetCncMonthData(date);
      }
      else {
        date.setTime(k);
        date.setDate(1);
        setTime(date, 0);
        starttime = getMonthDayTime(date, 1, 1);
        date.setMonth(date.getMonth() + 1); // 下一个月的1号
        endtime = getMonthDayTime(date, 1, 1);
        console.log('由于删除了休假/加班设置，重新计算该月的稼动率统计', starttime);
        await CalcOeeAgain(null, starttime, endtime);
        if (i > date.getTime()) // 跨越月份
        {
          starttime = endtime;
          date.setMonth(date.getMonth() + 1); // 下一个月的1号
          endtime = getMonthDayTime(date, 1, 1);
          console.log('由于删除了休假/加班设置，重新计算该月的稼动率统计', starttime);
          await CalcOeeAgain(null, starttime, endtime);
        }
      }
    }
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('Failed to DeleteCncAdjustTime: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

function mkdirSync(filePath) {
  if (fs.existsSync(filePath))
    return true;
  if (mkdirSync(path.dirname(filePath))) {
    fs.mkdirSync(filePath);
    return true;
  }
}

//FSMS
app.post('/Upload', async (req, res) => {
  let body = req.body;
  if (body.unionorder == undefined || body.workorder == undefined || body.filename == undefined || body.filedata == undefined) {
    if (body.unionorder == undefined)
      console.log('Upload failed, unionorder is null');
    else if (body.workorder == undefined)
      console.log('Upload failed, workorder is null');
    else if (body.fileName == undefined)
      console.log('Upload failed, filename is null');
    else
      console.log('Upload failed, filedata is null');
    res.status(200);
    res.json({ "result": "error", "description": "unionorder or workorder or filename or filedata is not set" });
    return;
  }
  else {
    console.log("请求上传 " + body.unionorder + "/" + body.workorder + "/" + body.filename + " (" + body.filedata.length + " bytes)");
  }
  let date = new Date();
  let filePath = "./public/" + body.unionorder;
  let index = body.filename.lastIndexOf('.');
  let filename = "";
  let ext = "";
  if (index > 0) {
    filename = body.filename.substr(0, index);
    ext = body.filename.substr(index).toLowerCase(); // PDF文件在解析时只能识别后缀为小写pdf的文件，故后缀改为小写
  }
  else {
    filename = body.filename;
  }
  mkdirSync(filePath);
  filePath += '/';
  filePath += filename;
  filePath += ext;
  let responseBody = {};
  try {
    let rawData = body.filedata;
    index = rawData.indexOf("base64,");
    if (index < 5) {
      console.log('Failed to upload, not a base64 file: ' + body.filename);
      res.status(200);
      res.json({ "result": "error", "description": "not find base64 flag" });
      return;
    }
    index += 7;
    let base64Data = rawData.substr(index);
    let data = Buffer.from(base64Data, 'base64');
    fs.writeFileSync(filePath, data);
    console.log('file saved' + " (" + data.length + " bytes)");

    // 先判断是不是工联单所需的BOM文件
    if (ext == '.xlsx' || ext == '.xls') {
      let sql = "select id from machining_union_sheet where union_order = '" + body.unionorder + "' and name = '" + body.workorder + "'";
      let suc = await db_util.query(sql);
      if (suc.length > 0) {
        let ret = await CheckBOMFile(filePath, body.unionorder);
        if (ret.length > 0) {
          res.status(200);
          res.json({ "result": "error", "description": ret });
          return;
        }
      }
      else if (body.unionorder != 'warehouse') {
        console.log('上传的Excel文件不是BOM表，因为在总表中找不到工联单号是', body.unionorder, '和治具名称是', body.workorder, '的记录');
      }
    }
    let upload_time = getMonthDayTime(date, 1, 1);
    let sql = "select * from machining_files where union_order = '" + body.unionorder + "' and sheet_order = '" + body.workorder + "' and file_path = '" + filePath + "'";
    let suc = await db_util.query(sql);
    if (suc.length == 0)
      sql = "insert into machining_files (union_order, sheet_order, file_path, file_name, upload_time, file_status) values('" + body.unionorder + "', '" + body.workorder + "', '" + filePath + "', '" + body.filename + "', '" + upload_time + "', '0')";
    else
      sql = "update machining_files set upload_time = '" + upload_time + "', file_status = '0' where id = " + suc[0].id + "";
    let sucData = await db_util.query(sql);
    if (body.unionorder == "warehouse") {
      let array = await ParseWarehouseFile(filePath);
      res.status(200);
      res.json({ "result": "ok", "order": array });
    }
    else { // 2022-12-14加入下来的代码，2021-10-08取消此功能
      /*if( suc.length == 0 )
      {
        sql = "select id, imagefile from machining_sheet where union_order = '"+ body.unionorder +"' and sheet_order = '"+ body.workorder +"'";
        let succ2 = await db_util.query(sql);
        if( succ2.length > 0 )
        {
          filePath = "";
          if( succ2[0].imagefile != '' )
          {
            filePath = succ2[0].imagefile + ',';
          }
          filePath += body.unionorder;
          filePath += '/';
          filePath += filename;
          filePath += ext;
          sql = "update machining_sheet set imagefile = '"+ filePath +"' where id = '"+ succ2[0].id +"'";
          await db_util.query(sql);
        }
      }*/
      res.status(200);
      if (suc.length == 0)
        res.json({ "result": "ok", "new keyID": sucData.insertId });
      else
        res.json({ "result": "ok", "old keyID": suc[0].id, "affectedRows": sucData.affectedRows });
    }
  }
  catch (error) {
    console.log("上传出错: " + error.message);
    responseBody = JSON.stringify({ result: "error", description: error.message });
    res.status(200).end(responseBody.toString());
  }
})

//NOUSE
app.post('/CollectData', function (req, res) {
  var body = req.body;
  var sql = "select id from cncdata where Time = '" + body.Time + "'";
  db_util.ExecuteSQL(sql, null,
    (suc1) => {
      if (suc1.length == 0) {
        var operatingstatus = "";
        if (body.operatingstatus != undefined)
          operatingstatus = body.operatingstatus;
        var operatingmode = "";
        if (body.operatingmode != undefined)
          operatingmode = body.operatingmode;
        var alarmstatus = "False";
        if (body.Errcode != undefined)
          alarmstatus = body.Errcode;
        else if (body.alarmstatus != undefined)
          alarmstatus = body.alarmstatus;
        var cycletime = "";
        //if( body.cycletime != undefined )
        //  cycletime = body.cycletime;
        var operatingtime = "";
        if (body.operatingtime != undefined)
          operatingtime = body.operatingtime;
        var partcount = "";
        if (body.partcount != undefined)
          partcount = body.partcount;
        var feedrate = "";
        if (body.feedratecmd != undefined)
          feedrate = body.feedratecmd;
        else if (body.feedrate != undefined)
          feedrate = body.feedrate;
        var feedrateoverride = "";
        if (body.feedrateoverride != undefined)
          feedrateoverride = body.feedrateoverride;
        var program = "";
        if (body.program != undefined)
          program = body.program;
        var actualspeed = "";
        if (body.spindlespeedcmd != undefined)
          actualspeed = body.spindlespeedcmd;
        else if (body.actualspeed != undefined)
          actualspeed = body.actualspeed;
        var speedoverride = "";
        if (body.speedoverride != undefined)
          speedoverride = body.speedoverride;
        var activetoolid = "";
        if (body.activetoolid != undefined)
          activetoolid = body.activetoolid;
        if (activetoolid == "" || activetoolid == "0") {
          if (body.toolidcmd != undefined)
            activetoolid = body.toolidcmd;
        }
        sql = "insert into cncdata values(null, '" + body.evt_type + "', '" + body.MachineName + "', '', '" + body.Time + "', '" + body.LocalTime + "', '" + body.Operation_Mode + "', '', '" + operatingstatus + "', '" + operatingmode + "', '" + alarmstatus + "', '" + cycletime + "', '" + operatingtime + "', '" + partcount + "', '" + feedrate + "', '" + feedrateoverride + "', '" + program + "', '" + actualspeed + "', '" + speedoverride + "', '" + activetoolid + "')";
        db_util.ExecuteSQL(sql, null,
          (suc2) => {
            g_lastUpdateTime = Date.now();
            for (var i = 0; i < g_cncInfo.length; i++) {
              if (g_cncInfo[i].MachineName == body.MachineName) {
                if (g_cncInfo[i]["lastmode"] != body.Operation_Mode) {
                  g_cncInfo[i]["lastmode"] = body.Operation_Mode;
                  g_cncInfo[i]["lastmode_starttime"] = body.Time;
                }
                g_cncInfo[i]["lastmode_lasttime"] = body.Time;
                break;
              }
            }
            if ((suc2.insertId % 500) == 0) // 每500条log一次，每条一次量太大了
              console.log('Succeeded to insert cncdata: ' + body.Time + ' [' + body.LocalTime + '] at ' + suc2.insertId);
            res.status(200);
            res.json({ "result": "ok" });
          },
          (err2) => {
            console.log('Failed to insert cncdata: ' + body.Time + ', ' + err2.message);
            res.status(200);
            res.json({ "result": "error", "description": (body.Time + ', ' + err2.message) });
          }
        );
      }
      else {
        var date = new Date(body.Time);
        console.log('The data exists, id = ' + suc1[0].id + ', Time = ' + body.Time + ' [' + getMonthDayTime(date, 1, 1) + ']');
        res.status(200);
        res.json({ "result": "error", "description": "the data existed already" });
      }
    },
    (err1) => {
      console.log('Failed to CollectData ' + body.Time + ', ' + err1.message);
      res.status(200);
      res.json({ "result": "error", "description": err1.message });
    }
  );
})

//NOUSE
app.post('/CollectDataBlock', async (req, res) => {
  let body = req.body;
  if (body.items == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "items is undefined" });
    return;
  }
  let sql = "";
  let operatingstatus = "";
  let operatingmode = "";
  let alarmstatus = "";
  let data = new Array();
  let wait_time = g_nOffTime / 10;
  let i = 0, k = 0;
  for (i = 0; i < body.items.length; i++) {
    for (k = 0; k < data.length; k++) {
      if (data[k][2] == body.items[i].MachineName && data[k][1] == body.items[i].evt_type && data[k][6] == body.items[i].Operation_Mode) {
        //console.log(body.items[i].MachineName + ' more than 1 times: ' + body.items[i].Time + ', ' + data[k][4]);
        break;
      }
    }
    if (k < data.length) {
      continue;
    }
    operatingstatus = "";
    operatingmode = "";
    alarmstatus = "";
    if (body.items[i].operatingstatus != undefined)
      operatingstatus = body.items[i].operatingstatus;
    if (body.items[i].operatingmode != undefined)
      operatingmode = body.items[i].operatingmode;
    if (body.items[i].Errcode != undefined)
      alarmstatus = body.items[i].Errcode;
    else if (body.items[i].alarmstatus != undefined)
      alarmstatus = body.items[i].alarmstatus;
    sql = "select evt_type, Time, Operation_Mode, operatingstatus, operatingmode, alarmstatus from cncdata where MachineName = '" + body.items[i].MachineName + "' ORDER BY id DESC LIMIT 1";
    let succ2 = await db_util.query(sql);
    if (succ2.length > 0) {
      let lastTime = parseInt(succ2[0].Time);
      let currentTime = parseInt(body.items[i].Time);
      if (currentTime < (lastTime + wait_time)) {
        if (succ2[0].evt_type == body.items[i].evt_type && succ2[0].Operation_Mode == body.items[i].Operation_Mode &&
          succ2[0].operatingstatus == operatingstatus && succ2[0].operatingmode == operatingmode && succ2[0].alarmstatus == alarmstatus) {
          continue;
        }
      }
    }
    let temp = new Array(20);
    temp[0] = null;
    temp[1] = body.items[i].evt_type;
    temp[2] = body.items[i].MachineName;
    temp[3] = "";//body.items[i].MachineSN;
    temp[4] = body.items[i].Time;
    temp[5] = body.items[i].LocalTime;
    temp[6] = body.items[i].Operation_Mode;
    temp[7] = "";//body.items[i].Spindle_rated_load;
    temp[8] = operatingstatus;
    temp[9] = operatingmode;
    temp[10] = alarmstatus;
    //if( body.items[i].cycletime == undefined )
    temp[11] = "";
    //else
    //  temp[11] = body.items[i].cycletime;
    if (body.items[i].operatingtime == undefined)
      temp[12] = "";
    else
      temp[12] = body.items[i].operatingtime;
    if (body.items[i].partcount == undefined)
      temp[13] = "";
    else
      temp[13] = body.items[i].partcount;
    if (body.items[i].feedratecmd != undefined)
      temp[14] = body.items[i].feedratecmd;
    else if (body.items[i].feedrate != undefined)
      temp[14] = body.items[i].feedrate;
    else
      temp[14] = "";
    if (body.items[i].feedrateoverride == undefined)
      temp[15] = "";
    else
      temp[15] = body.items[i].feedrateoverride;
    if (body.items[i].program == undefined)
      temp[16] = "";
    else
      temp[16] = body.items[i].program;
    if (body.items[i].spindlespeedcmd != undefined)
      temp[17] = body.items[i].spindlespeedcmd;
    else if (body.items[i].actualspeed != undefined)
      temp[17] = body.items[i].actualspeed;
    else
      temp[17] = "";
    if (body.items[i].speedoverride == undefined)
      temp[18] = "";
    else
      temp[18] = body.items[i].speedoverride;
    if (body.items[i].activetoolid == undefined)
      temp[19] = "";
    else
      temp[19] = body.items[i].activetoolid;
    if (temp[19] == "" || temp[19] == "0") {
      if (body.items[i].toolidcmd != undefined)
        temp[19] = body.items[i].toolidcmd;
    }
    data.push(temp);
    // 这里没有设置当前状态的开始时间
  }
  if (data.length == 0) {
    //console.log('数据忽略：' + body.items.length);
    res.status(200);
    res.json({ "result": "ok", "lastID": 0 });
    return;
  }
  sql = "insert into cncdata values ?";
  db_util.ExecuteSQL(sql, [data],
    (suc) => {
      g_lastUpdateTime = Date.now();
      let id = suc.insertId + suc.affectedRows - 1;
      for (let i = suc.insertId; i <= id; i++) {
        if ((i % 500) == 0) {
          let date = new Date();
          console.log('Succeeded to insert into cncdata ' + data.length + ' values to ' + id + ' on ' + getMonthDayTime(date, 1, 1));
          break;
        }
      }
      res.status(200);
      res.json({ "result": "ok", "lastID": id });
    },
    (err) => {
      let msg = err.message;
      msg += ('. data from ' + body.items[0].Time + ' to ' + body.items[body.items.length - 1].Time);
      console.log('Failed to insert CollectDataBlock: ' + msg);
      res.status(200);
      res.json({ "result": "error", "description": msg });
    }
  );
})

//NOUSE
app.post('/QueryCncOther', async (req, res) => {
  let json = { "result": "ok", "name": req.body.name, "value": 0 };
  let sql = "select * from cncother where name = '" + req.body.name + "'";
  try {
    let suc = await db_util.query(sql);
    if (suc.length > 0) {
      json['value'] = suc[0]['value'];
    }
    else {
      if (json['name'] == 'jiadonglvValue')
        json['value'] = 90;
      else if (json['name'] == 'OEEValue')
        json['value'] = 90;
      else if (json['name'] == 'timeValue')
        json['value'] = 5;
    }
  }
  catch (error) {
    console.log('QueryCncOther', sql, error.message);
  }
  res.status(200);
  res.json(json);
})

//NOUSE
app.post('/AddCncOther', function (req, res) {
  var sql = "select * from cncother where name = '" + req.body.name + "'";
  db_util.ExecuteSQL(sql, null,
    (suc) => {
      if (suc.length > 0) {
        sql = "update cncother set value = '" + req.body.value + "' where name = '" + req.body.name + "'";
        db_util.ExecuteSQL(sql, null,
          (suc2) => {
            res.status(200);
            res.json({ "result": "ok", "description": "update the name value" });
          },
          (err2) => {
            res.status(200);
            res.json({ "result": "error", "description": err2.message });
          }
        );
      }
      else {
        sql = "insert into cncother (name, value) values('" + req.body.name + "', '" + req.body.value + "')";
        db_util.ExecuteSQL(sql, null,
          (suc3) => {
            res.status(200);
            res.json({ "result": "ok" });
          },
          (err3) => {
            res.status(200);
            res.json({ "result": "error", "description": err3.message });
          }
        );
      }
    },
    (err) => {
      res.status(200);
      res.json({ "result": "error", "description": err.message });
    }
  );
})

//NOUSE
app.post('/UpdateCncOther', function (req, res) {
  var sql = "update cncother set value = '" + req.body.value + "' where name = '" + req.body.name + "'";
  db_util.ExecuteSQL(sql, null,
    (suc) => {
      res.status(200);
      res.json({ "result": "ok" });
    },
    (err) => {
      res.status(200);
      res.json({ "result": "error", "description": err.message });
    }
  );
})

//NOUSE
app.post('/DeleteCncOther', function (req, res) {
  var sql = "delete from cncother where name = '" + req.body.name + "'";
  db_util.ExecuteSQL(sql, null,
    (suc) => {
      res.status(200);
      res.json({ "result": "ok" });
    },
    (err) => {
      res.status(200);
      res.json({ "result": "error", "description": err.message });
    }
  );
})

//FSMS
app.post('/QueryDeliveryOrder', async (req, res) => {
  try {
    let i, k;
    let sql = "";
    let ret = await db_util.query("select * from delivery_sheet");
    let suc = await db_util.query("select union_order, p79_id, paijian_time from machining_union_sheet where p79_id > 0");
    for (i = 0; i < ret.length; i++) {
      ret[i]["OwnerName"] = "";
      ret[i]["OwnerTel"] = "";
      ret[i]['sorttime'] = ret[i]['starttime'];
      for (k = 0; k < suc.length; k++) {
        if (suc[k]["union_order"] == ret[i]["union_order"]) {
          ret[i]['sorttime'] = suc[k]['paijian_time'];
          sql = "select RequestOwnerName, RequestOwnerTel from p79_tofsms where id = " + suc[k]["p79_id"] + "";
          let succ2 = await db_util.query(sql);
          if (succ2.length > 0) {
            ret[i]["OwnerName"] = succ2[0]["RequestOwnerName"];
            ret[i]["OwnerTel"] = succ2[0]["RequestOwnerTel"];
          }
          break;
        }
      }
    }
    ret.sort(keysort('sorttime', false));
    for (i = 0; i < ret.length; i++) {
      ret[i]['sorttime'] = '';
    }

    // const sortedData = ret.sort((a, b) => {
    //   const prefixA = a.union_order.substring(0, 3);
    //   const prefixB = b.union_order.substring(0, 3);

    //   if (prefixA==='WRKS' && prefixB!=='WRKS') {
    //     return -1;
    //   } else if (prefixA!=='WRKS' && prefixB==='WRKS') {
    //     return 1;
    //   } else {
    //     const numberA = (a.union_order.substring(4));
    //     const numberB = (b.union_order.substring(4));
    //     if(numberA<numberB) return -1; // 根据数字部分升序排序
    //   }
    // });

    // console.log('排序后的数据：'+sortedData);

    res.status(200);
    res.json({ "result": "ok", "order": ret });
  }
  catch (error) {
    console.log('QueryDeliveryOrder failed, ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//NOUSE
app.post('/AddDeliveryOrder', async (req, res) => {
  if (req.body.unionorder == undefined || req.body.quatity == undefined || req.body.lingqu_ren == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set unionorder or quatity or lingqu_ren" });
    return;
  }
  let quatity = parseFloat(req.body.quatity);
  if (quatity <= 0) {
    res.status(200);
    res.json({ "result": "error", "description": "quatity is less than 0" });
    return;
  }
  try {
    let json = { "result": "ok" };
    let sql = "select name, delivery_addr from machining_union_sheet where union_order = '" + req.body.unionorder + "'";
    let ret = await db_util.query(sql);
    if (ret.length > 0) {
      sql = "insert into delivery_sheet values('" + req.body.unionorder + "', '" + ret[0].name + "', '" + req.body.quatity + "', '" + ret[0].delivery_addr + "', '', '', '" + req.body.lingqu_ren + "')";
      let ret2 = await db_util.query(sql);
      //json["id"] = ret2.insertId;
    }
    else {
      json["result"] = "error";
      json["description"] = "not find the unionorder";
    }
    res.status(200);
    res.json(json);
  }
  catch (error) {
    console.log('AddDeliveryOrder failed, ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/UpdateDeliveryOrder', function (req, res) {
  let body = req.body;
  let sql = "Update delivery_sheet set ";
  sql += body.name1;
  sql += " = '" + body.newValue1 + "'";
  if (body.name2 != undefined) {
    sql += ", ";
    sql += body.name2;
    sql += " = '" + body.newValue2 + "'";
  }
  if (body.name3 != undefined) {
    sql += ", ";
    sql += body.name3;
    sql += " = '" + body.newValue3 + "'";
  }
  sql += " where union_order='" + body.unionorder + "'";
  console.log(sql);
  db_util.ExecuteSQL(sql, null,
    (sucData) => {
      console.log(sucData.message);
      res.status(200);
      res.json({ "result": "ok", "description": sucData.message });
    },
    (errData) => {
      res.status(200);
      res.json({ "result": "error", "errorCode": "1", "description": errData.message });
      console.log(sql);
    }
  );
})

//FSMS
app.post('/QueryBaseMaterial', async (req, res) => {
  try {
    var sql = "select * from base_material";
    if (req.body.material_no != undefined)
      sql += " where material_no = '" + req.body.material_no + "'";
    else if (req.body.keyword != undefined)
      sql += " where material_no like '%" + req.body.keyword + "%' or name like '%" + req.body.keyword + "%' or shelf_position like '%" + req.body.keyword + "%'";
    let ret = await db_util.query(sql);
    for (let i = 0; i < ret.length; i++) {
      if (ret[i]["stock"] == '')
        ret[i]["stock"] = "0";
      else
        ret[i]["stock"] = dotFixed(ret[i]["stock"]);
    }
    if (req.body.name != undefined) {
      let date = new Date();
      let currentmonth = getMonthDayTime(date);
      date.setMonth(date.getMonth() - 1);
      let previousmonth = getMonthDayTime(date);
      date.setMonth(date.getMonth() - 1);
      let previous2month = getMonthDayTime(date);
      let starttime = previous2month + "-01 00:00:00";
      for (let i = 0; i < ret.length; i++) {
        sql = "select * from material_send where material_no = '" + ret[i].material_no + "' and timestamp > '" + starttime + "'";
        ret[i]["currentmonth"] = 0;
        ret[i]["previousmonth"] = 0;
        ret[i]["previous2month"] = 0;
        let suc2 = await db_util.query(sql);
        for (let k = 0; k < suc2.length; k++) {
          sql = suc2[k].timestamp.substr(0, 7);
          if (sql == currentmonth) {
            ret[i]["currentmonth"] += parseFloat(suc2[k].quatity);
          }
          else if (sql == previousmonth) {
            ret[i]["previousmonth"] += parseFloat(suc2[k].quatity);
          }
          else if (sql == previous2month) {
            ret[i]["previous2month"] += parseFloat(suc2[k].quatity);
          }
        }

        ret[i]["cost"] = 0;
        sql = "select * from warehouse where material_no = '" + ret[i].material_no + "'";
        let succ3 = await db_util.query(sql);
        for (let j = 0; j < succ3.length; j++) {
          let price = parseFloat(succ3[j].price) * (parseFloat(succ3[j].quatity) - parseFloat(succ3[j].usedQuatity));
          let cost = await GetPriceAfterTax(price, succ3[j].manufacturer, 2);
          ret[i]["cost"] += cost;
        }
        ret[i]["cost"] = dotFixed(ret[i]["cost"]);
      }
    }
    res.status(200);
    res.json({ "result": "ok", "order": ret });
  }
  catch (error) {
    console.log('QueryBaseMaterial error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/AddBaseMaterial', async (req, res) => {
  if (req.body.material_no == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set material_no" });
    return;
  }
  try {
    var sql = "select * from base_material where material_no = '" + req.body.material_no + "'";
    let ret = await db_util.query(sql);
    if (ret.length > 0) {
      var flag = false;
      sql = "update base_material set ";
      if (req.body.name != undefined) {
        if (flag)
          sql += ", ";
        sql += "name = '" + req.body.name + "'";
        flag = true;
      }
      if (req.body.type != undefined) {
        if (flag)
          sql += ", ";
        sql += "type = '" + req.body.type + "'";
        flag = true;
      }
      if (req.body.unit != undefined) {
        if (flag)
          sql += ", ";
        sql += "unit = '" + req.body.unit + "'";
        flag = true;
      }
      if (req.body.safe_stock != undefined) {
        if (flag)
          sql += ", ";
        sql += "safe_stock = '" + req.body.safe_stock + "'";
        flag = true;
      }
      if (req.body.shelf_position != undefined) {
        if (flag)
          sql += ", ";
        sql += "shelf_position = '" + req.body.shelf_position + "'";
        flag = true;
      }
      if (req.body.remark != undefined) {
        if (flag)
          sql += ", ";
        sql += "remark = '" + req.body.remark + "'";
        flag = true;
      }
      if (flag == false) {
        res.status(200);
        res.json({ "result": "error", "description": "no column was matched to update" });
        console.log('Failed, no column was matched to update base_material');
        return;
      }
      sql += " where material_no = '" + req.body.material_no + "'";
    }
    else {
      var safe_stock = "";
      if (req.body.safe_stock != undefined)
        safe_stock = req.body.safe_stock;
      sql = "insert into base_material values('" + req.body.material_no + "', '" + req.body.name + "', '" + req.body.type + "', '" + req.body.unit + "', '" + safe_stock + "', '0', '" + req.body.shelf_position + "', '" + req.body.remark + "')";
    }
    console.log(sql);
    let suc = await db_util.query(sql);
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('AddBaseMaterial error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//NOUSE
app.post('/UpdateMaterialStock', async (req, res) => {
  if (req.body.material_no == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set material_no" });
    return;
  }
  try {
    var sql = "select stock from base_material where material_no = '" + req.body.material_no + "'";
    let ret = await db_util.query(sql);
    if (ret.length > 0) {
      var count = parseFloat(ret[0].stock);
      if (isNaN(count))
        count = 0;
      var cnt = parseFloat(req.body.stock);
      if (isNaN(cnt))
        cnt = 0;
      cnt += count;
      count = dotFixed(cnt, 3);
      sql = "update base_material set stock = '" + count + "' where material_no = '" + req.body.material_no + "'";
      await db_util.query(sql);
      res.status(200);
      res.json({ "result": "ok" });
    }
    else {
      res.status(200);
      res.json({ "result": "error", "description": "not material_no was matched" });
    }
  }
  catch (error) {
    console.log('UpdateMaterialStock error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/DeleteBaseMaterial', async (req, res) => {
  if (req.body.material_no == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set material_no" });
    return;
  }
  try {
    var sql = "delete from base_material where material_no = '" + req.body.material_no + "'";
    let suc = await db_util.query(sql);
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('DeleteBaseMaterial error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryFirmInfo', async (req, res) => {
  try {
    let ret = await db_util.query("select * from firm_info");
    res.status(200);
    res.json({ "result": "ok", "order": ret });
  }
  catch (error) {
    console.log('QueryFirmInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/AddFirmInfo', async (req, res) => {
  try {
    var sql = "select * from firm_info where fullname = '" + req.body.fullname + "'";
    let ret = await db_util.query(sql);
    if (ret.length > 0) {
      var flag = false;
      sql = "update firm_info set ";
      if (req.body.shortname != undefined) {
        if (flag)
          sql += ", ";
        sql += "shortname = '" + req.body.shortname + "'";
        flag = true;
      }
      if (req.body.tax_rate != undefined) {
        if (flag)
          sql += ", ";
        sql += "tax_rate = '" + req.body.tax_rate + "'";
        flag = true;
      }
      if (flag == false) {
        res.status(200);
        res.json({ "result": "error", "description": "no column was matched to update" });
        console.log('Failed, no column was matched to update firm_info');
        return;
      }
      sql += " where fullname = '" + req.body.fullname + "'";
    }
    else {
      if (req.body.shortname != undefined)
        sql = "insert into firm_info values('" + req.body.fullname + "', '" + req.body.shortname + "', '" + req.body.tax_rate + "')";
      else
        sql = "insert into firm_info values('" + req.body.fullname + "', '', '" + req.body.tax_rate + "')";
    }
    let suc = await db_util.query(sql);
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('AddFirmInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/DeleteFirmInfo', async (req, res) => {
  try {
    var sql = "delete from firm_info where fullname = '" + req.body.fullname + "'";
    let suc = await db_util.query(sql);
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('DeleteFirmInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

function dotFixed(floatValue, number) // 字符串，小数点后面的位数
{
  if (floatValue == undefined || floatValue == 'NaN' || floatValue == '')
    return 0;
  let str = "";
  if ("string" != typeof floatValue)
    str = floatValue.toString();
  else
    str = floatValue;
  let index = str.indexOf('.');
  if (index < 0)
    return parseFloat(str);
  let count = 2;
  if (number != undefined) {
    count = parseInt(number);
    if (isNaN(count))
      count = 2;
  }
  if (str.split('.')[1].length <= count)
    return parseFloat(str);
  let temp = parseFloat(str).toFixed(count);
  return parseFloat(temp);
}

//FSMS
app.post('/QueryWarehouse', async (req, res) => {
  try {
    var sql = "select * from warehouse";
    if (req.body.material_no != undefined)
      sql += " where material_no = '" + req.body.material_no + "'";
    else if (req.body.keyword != undefined)
      sql += " where material_no like '%" + req.body.keyword + "%' OR PR_NO like '%" + req.body.keyword + "%' OR PO_NO like '%" + req.body.keyword + "%' OR manufacturer like '%" + req.body.keyword + "%'";
    let suc = await db_util.query(sql);
    var array = new Array();
    var i = 0;
    var count = 50;
    if (req.body.offset != undefined) {
      i = parseInt(req.body.offset);
      if (isNaN(i))
        i = 0;
    }
    if (req.body.count != undefined) {
      count = parseInt(req.body.count);
      if (isNaN(count))
        count = 50;
    }
    var index = -1;
    suc.forEach(element => {
      index++;
      if (index >= i) {
        if (array.length < count) {
          element["quatity"] = dotFixed(element["quatity"]);
          array.push(element);
        }
      }
    });
    res.status(200);
    res.json({ "result": "ok", "order": array, "total_count": suc.length });
  }
  catch (error) {
    console.log('QueryWarehouse error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//NOUSE
app.post('/AddWarehouse', async (req, res) => {
  try {
    var quatity = 0.0;
    var sql = "select * from warehouse where material_no = '" + req.body.material_no + "'";
    let ret = await db_util.query(sql);
    if (ret.length > 0) {
      quatity = parseFloat(ret[0].quatity);
      if (isNaN(quatity))
        quatity = 0.0;
      var flag = false;
      sql = "update warehouse set ";
      if (req.body.PR_NO != undefined) {
        if (flag)
          sql += ", ";
        sql += "PR_NO = '" + req.body.PR_NO + "'";
        flag = true;
      }
      if (req.body.PO_NO != undefined) {
        if (flag)
          sql += ", ";
        sql += "PO_NO = '" + req.body.PO_NO + "'";
        flag = true;
      }
      if (req.body.SN != undefined) {
        if (flag)
          sql += ", ";
        sql += "SN = '" + req.body.SN + "'";
        flag = true;
      }
      if (req.body.quatity != undefined) {
        if (flag)
          sql += ", ";
        sql += "quatity = '" + req.body.quatity + "'";
        flag = true;
        let temp = parseFloat(req.body.quatity);
        if (isNaN(temp))
          temp = 0.0;
        temp -= quatity;
        quatity = dotFixed(temp, 3);
      }
      if (req.body.price != undefined) {
        if (flag)
          sql += ", ";
        sql += "price = '" + req.body.price + "'";
        flag = true;
      }
      if (req.body.manufacturer != undefined) {
        if (flag)
          sql += ", ";
        sql += "manufacturer = '" + req.body.manufacturer + "'";
        flag = true;
      }
      if (req.body.currency != undefined) {
        if (flag)
          sql += ", ";
        sql += "currency = '" + req.body.currency + "'";
        flag = true;
      }
      if (req.body.check_no != undefined) {
        if (flag)
          sql += ", ";
        sql += "check_no = '" + req.body.check_no + "'";
        flag = true;
      }
      if (req.body.purchasing_reason != undefined) {
        if (flag)
          sql += ", ";
        sql += "purchasing_reason = '" + req.body.purchasing_reason + "'";
        flag = true;
      }
      if (flag == false) {
        res.status(200);
        res.json({ "result": "error", "description": "no column was matched to update" });
        console.log('Failed, no column was matched to update base_material');
        return;
      }
      sql += " where material_no = '" + req.body.material_no + "'";
    }
    else {
      quatity = parseFloat(req.body.quatity);
      if (isNaN(quatity))
        quatity = 0.0;
      sql = "insert into warehouse values('" + req.body.PR_NO + "', '" + req.body.PO_NO + "', '" + req.body.SN + "', '" + req.body.material_no + "', '" + req.body.quatity + "', '" + req.body.price + "', '" + req.body.manufacturer + "', '" + req.body.currency + "', '" + req.body.check_no + "', '" + req.body.purchasing_reason + "')";
    }
    let suc = await db_util.query(sql);
    sql = "select stock from base_material where material_no = '" + req.body.material_no + "'";
    let succ2 = await db_util.query(sql);
    if (succ2.length > 0) {
      var stock = parseFloat(succ2[0].stock);
      if (isNaN(stock))
        stock = 0;
      stock += quatity;
      sql = "update base_material set stock = '" + dotFixed(stock, 3) + "' where material_no = '" + req.body.material_no + "'";
      await db_util.query(sql);
    }
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('AddWarehouse error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/DeleteWarehouse', async (req, res) => {
  if (req.body.id == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not set id" });
    return;
  }
  try {
    var quatity = 0.0;
    var usedQuatity = 0.0;
    var material_no = "";
    var sql = "select * from warehouse where id = '" + req.body.id + "'";
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      res.status(200);
      res.json({ "result": "error", "description": "the id does not exist" });
      return;
    }
    material_no = suc[0].material_no;
    quatity = parseFloat(suc[0].quatity);
    if (isNaN(quatity))
      quatity = 0;
    usedQuatity = parseFloat(suc[0].usedQuatity);
    if (isNaN(usedQuatity))
      usedQuatity = 0;
    sql = "delete from warehouse where id = '" + req.body.id + "'";
    await db_util.query(sql);
    sql = "select stock from base_material where material_no = '" + material_no + "'";
    let succ2 = await db_util.query(sql);
    if (succ2.length > 0) {
      var stock = parseFloat(succ2[0].stock);
      if (isNaN(stock))
        stock = 0;
      stock -= (quatity - usedQuatity);
      sql = "update base_material set stock = '" + dotFixed(stock, 3) + "' where material_no = '" + material_no + "'";
      await db_util.query(sql);
    }
    else {
      console.log('Deletewarehouse: the material_no not exist in base_material, ' + material_no);
    }
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('DeleteWarehouse error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

function keysort(key, sortType, key2) // sortType: true/降序；false/升序
{
  return function (o, p) {
    let a = o[key];
    let b = p[key];
    if (a == b) {
      if (key2 == undefined)
        return 0;
      a = o[key2];
      b = p[key2];
      if (a == b)
        return 0;
      if (sortType) {
        if (a < b)
          return 1;
        else
          return -1;
      }
      else {
        if (a < b)
          return -1;
        else
          return 1;
      }
    }
    if (sortType) {
      if (a < b)
        return 1;
      else
        return -1;
    }
    else {
      if (a < b)
        return -1;
      else
        return 1;
    }
  }
}

//FSMS
app.post('/QueryMaterialSend', async (req, res) => {
  try {
    let type = 0; // 1/加工件；2/标准件；3/物料申请单
    let status = 0; // 1/备料中；2/已备料；3/缺料
    let tuidan = 0; // 0/不查退单标记；2/必须查退单标记
    let tuidan_flag = '0';
    if (req.body.tuidan != undefined) {
      tuidan = parseInt(req.body.tuidan);
      if (isNaN(tuidan))
        tuidan = 0;
    }
    if (req.body.type != undefined) {
      if (req.body.type != 'All') {
        type = parseInt(req.body.type);
        if (isNaN(type))
          type = 0;
      }
    }
    if (req.body.status != undefined) {
      if (req.body.status != 'All') {
        status = parseInt(req.body.status);
        if (isNaN(status))
          status = 0;
      }
    }
    //console.log('QueryMaterialSend', req.body);
    let i = 0, j = 0, k = 0;
    let array = new Array();
    let sql = "select * from base_material";
    let material = await db_util.query(sql);
    let filter_order = false;
    let filter_materialno = false;
    let filter_cnc = false;
    let filter_banci = false;
    let filter_box = false;
    let filter_jiagongriqi = false;
    if (req.body.unionorder != undefined && req.body.unionorder != '')
      filter_order = true;
    if (req.body.material_no != undefined && req.body.material_no != '')
      filter_materialno = true;
    if (req.body.cnc != undefined && req.body.cnc != '')
      filter_cnc = true;
    if (req.body.banci != undefined && req.body.banci != '' && req.body.banci != 'All')
      filter_banci = true;
    if (req.body.box != undefined && req.body.box != '' && req.body.box != 'All')
      filter_box = true;
    if (req.body.jiagongriqi != undefined && req.body.jiagongriqi != '')
      filter_jiagongriqi = true;
    sql = "select union_order, delivery_date, charge_department from machining_union_sheet where status = 0 and length(engineer) > 0 and stage != '0000000100'";
    if (filter_order)
      sql += " and union_order like '%" + req.body.unionorder + "%'";
    let suc = await db_util.query(sql); // 总表
    for (i = 0; i < suc.length; i++) {
      sql = "select * from machining_sheet where quatity != '0' and union_order = '" + suc[i].union_order + "'";
      /*if( type == 0 || type == 1 )
      {
        if( filter_materialno )
          sql += " and material_no like '%"+ req.body.material_no +"%'";
      }*/
      if (type != 3) {
        if (filter_materialno)
          sql += " and material_no like '%" + req.body.material_no + "%'";
        if (filter_box)
          sql += " and box like '%" + req.body.box + "%'";
      }
      let suc2 = await db_util.query(sql); // 大表
      //if( suc2.length == 0 )
      //  continue;

      if (type == 0 || type == 1) {
        sql = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and rawdata != 0";
        if (status == 1 || status == 2) // =3（缺料）时表中的数据状态是1（备料中）
          sql += " and beiliao_ztai = '" + status + "'";
        sql += " and xlcc_x != '' and xlcc_y != '' and xlcc_z != ''";
        if (filter_cnc)
          sql += " and cnc like '%" + req.body.cnc + "%'";
        if (filter_box)
          sql += " and box like '%" + req.body.box + "%'";
        if (filter_materialno)
          sql += " and material_no like '%" + req.body.material_no + "%'";
        if (tuidan == 1)
          sql += " and tuidan = '1'";
        let suc3 = await db_util.query(sql); // 小表
        for (j = 0; j < suc3.length; j++) {
          if (filter_jiagongriqi) {
            if (suc3[j].jiagongriqi.indexOf(req.body.jiagongriqi) < 0)
              continue;
          }
          if (filter_banci) {
            if (suc3[j].banci != req.body.banci)
              continue;
          }

          let json = {};
          json["id"] = suc3[j].id;
          json["union_order"] = suc[i].union_order; // 工联单号
          json["delivery_date"] = suc[i].delivery_date; // 治具交期
          json["charge_department"] = suc[i].charge_department;// 付费部门
          json["name"] = "";//suc3[j].ljmc; // 名称
          json["cnc"] = suc3[j].cnc; // 机台
          json["czhi"] = suc3[j].czhi; // 材质
          json["xlcc_x"] = suc3[j].xlcc_x; // 下料尺寸X
          json["xlcc_y"] = suc3[j].xlcc_y; // 下料尺寸Y
          json["xlcc_z"] = suc3[j].xlcc_z; // 下料尺寸Z
          json["xlcc_bs"] = suc3[j].xlcc_bs; // 板数
          json["xlcc_pb"] = suc3[j].xlcc_pb; // 拼板
          json["lingliao_ren"] = suc3[j].lingliao_ren; // 领料人
          json["lingliao_riqi"] = suc3[j].lingliao_riqi; // 领料日期
          json["lingliao_qixian"] = suc3[j].lingliao_qixian; // 领料期限
          json["lingliao_bzhu"] = suc3[j].lingliao_bzhu; // 领料备注
          json["box"] = suc3[j].box; // 箱号
          json["jiagongriqi"] = suc3[j].jiagongriqi;
          json["banci"] = suc3[j].banci;
          json["type_flag"] = "1"; // 标记：1/加工件；0/标准件
          json["yibei_shuliang"] = suc3[j].yibei_shuliang;
          json["tuiku_shuliang"] = dotFixed(suc3[j].tuiku_shuliang);
          json["beiliao_ztai"] = suc3[j].beiliao_ztai;
          json["material_no"] = suc3[j].material_no; // 料号
          json["quatity_total"] = dotFixed(suc3[j].gjsl); // 需求总量
          json["stock"] = '0';
          json["tuidan"] = suc3[j]["tuidan"];
          tuidan_flag = suc3[j]["tuidan"];
          for (k = 0; k < material.length; k++) {
            if (material[k].material_no == json["material_no"]) {
              json["name"] = material[k].name;
              json["unit"] = material[k].unit; // 单位
              json["position"] = material[k].shelf_position; // 架位
              json["stock"] = dotFixed(material[k].stock); // 现有库存
              let yibei = parseFloat(json["yibei_shuliang"]);
              let stockTemp = parseFloat(json["stock"]);
              let quatity_total = parseFloat(json["quatity_total"]);
              if (isNaN(yibei))
                yibei = 0.0;
              if (isNaN(stockTemp))
                stockTemp = 0.0;
              //if( json["stock"] == '0' || json["stock"] == '' )
              if ((yibei + stockTemp) < quatity_total)
                json["beiliao_ztai"] = 3;
              break;
            }
          }
          if (k == material.length) // 没找到
          {
            json["name"] = "";
            json["unit"] = "";
            json["position"] = "";
            json["stock"] = '0';
            json["beiliao_ztai"] = 3;
          }

          if (json["beiliao_ztai"] == 3) {
            if (status == 0 || status == 3)
              array.push(json);
          }
          else if (status == 0 || json["beiliao_ztai"] == status) {
            array.push(json);
          }
          if (json["beiliao_ztai"] != suc3[j].beiliao_ztai) {
            sql = "update dispatch_sheet set beiliao_ztai = '" + json["beiliao_ztai"] + "' where id = '" + suc3[j].id + "'";
            await db_util.query(sql);
            console.log('小表中预存的备料状态和实际状态不符：', suc3[j].beiliao_ztai, sql);
          }
        }
      }

      if (filter_cnc || filter_banci || filter_jiagongriqi)
        continue;
      if (type == 0 || type == 2) {
        // 加标准件
        for (k = 0; k < suc2.length; k++) {
          if (suc2[k].type_flag != 0)
            continue;
          //if( status != 0 && status != suc2[k].beiliao_ztai )
          //  continue;

          let json = {};
          json["id"] = parseInt(suc2[k].id) + 500000000;
          json["union_order"] = suc[i].union_order;
          json["delivery_date"] = suc[i].delivery_date;
          json["charge_department"] = suc[i].charge_department;
          json["name"] = suc2[k].sheet_order;
          json["cnc"] = "";
          json["czhi"] = "";
          json["xlcc_x"] = "";
          json["xlcc_y"] = "";
          json["xlcc_z"] = "";
          json["xlcc_bs"] = "";
          json["xlcc_pb"] = "";
          json["lingliao_ren"] = suc2[k].lingliao_ren;
          json["lingliao_riqi"] = suc2[k].lingliao_riqi;
          json["lingliao_qixian"] = suc2[k].lingliao_qixian;
          json["lingliao_bzhu"] = suc2[k].lingliao_bzhu;
          json["box"] = suc2[k].box;
          json["jiagongriqi"] = "";
          json["banci"] = "";
          json["type_flag"] = "0";
          json["material_no"] = suc2[k].material_no;
          json["quatity_total"] = dotFixed(suc2[k].quatity_total);
          json["yibei_shuliang"] = suc2[k].yibei_shuliang;
          json["tuiku_shuliang"] = dotFixed(suc2[k].tuiku_shuliang);
          json["beiliao_ztai"] = suc2[k].beiliao_ztai;
          json["stock"] = '0';
          json["tuidan"] = tuidan_flag;
          for (j = 0; j < material.length; j++) {
            if (material[j].material_no == json["material_no"]) {
              json["name"] = material[j].name;
              json["unit"] = material[j].unit;
              json["position"] = material[j].shelf_position;
              json["stock"] = dotFixed(material[j].stock);
              let yibei = parseFloat(json["yibei_shuliang"]);
              let stockTemp = parseFloat(json["stock"]);
              let quatity_total = parseFloat(json["quatity_total"]);
              if (isNaN(yibei))
                yibei = 0.0;
              if (isNaN(stockTemp))
                stockTemp = 0.0;
              //if( json["stock"] == '0' || json["stock"] == '' )
              if ((yibei + stockTemp) < quatity_total)
                json["beiliao_ztai"] = 3;
              break;
            }
          }
          if (j == material.length) // 没找到
          {
            json["name"] = "";
            json["unit"] = "";
            json["position"] = "";
            json["stock"] = '0';
            json["beiliao_ztai"] = 3;
          }
          if (json["beiliao_ztai"] == 3) {
            if (status == 0 || status == 3)
              array.push(json);
          }
          else if (status == 0 || json["beiliao_ztai"] == status) {
            array.push(json);
          }
          if (json["beiliao_ztai"] != suc2[k].beiliao_ztai) {
            sql = "update machining_sheet set beiliao_ztai = '" + json["beiliao_ztai"] + "' where id = '" + suc2[k].id + "'";
            await db_util.query(sql);
            console.log('大表中预存的备料状态和实际状态不符：', suc2[k].beiliao_ztai, sql);
          }
        }
      }
    }

    if (tuidan == 0 && (type == 0 || type == 3) && filter_cnc == false && filter_banci == false && filter_box == false && filter_jiagongriqi == false) {
      sql = "select * from material_apply where status = 'true' and lingliao_riqi = ''"; // 签核后才显示
      if (status == 1 || status == 2) // =3（缺料）时表中的数据状态是1（备料中）
        sql += " and beiliao_ztai = '" + status + "'";
      if (filter_materialno)
        sql += " and material_no like '%" + req.body.material_no + "%'";
      if (filter_order)
        sql += " and applyID like '%" + req.body.unionorder + "%'";
      let suc4 = await db_util.query(sql);
      for (i = 0; i < suc4.length; i++) {
        let json = {};
        json["id"] = parseInt(suc4[i].id) + 1800000000;
        json["union_order"] = suc4[i].applyID;
        json["delivery_date"] = "";
        json["charge_department"] = suc4[i].charge_department;
        json["name"] = suc4[i].name;
        json["cnc"] = "";
        json["czhi"] = "";
        json["xlcc_x"] = "";
        json["xlcc_y"] = "";
        json["xlcc_z"] = "";
        json["xlcc_bs"] = "";
        json["xlcc_pb"] = "";
        json["lingliao_ren"] = suc4[i].applicant;
        json["lingliao_riqi"] = "";
        json["lingliao_qixian"] = "";
        json["lingliao_bzhu"] = suc4[i].remark;
        json["box"] = "";
        json["jiagongriqi"] = "";
        json["banci"] = "";
        json["type_flag"] = "2";
        json["material_no"] = suc4[i].material_no;
        json["quatity_total"] = dotFixed(suc4[i].quatity);
        json["yibei_shuliang"] = suc4[i].yibei_shuliang;
        json["tuiku_shuliang"] = dotFixed(suc4[i].tuiku_shuliang);
        json["beiliao_ztai"] = suc4[i].beiliao_ztai;
        json["stock"] = '0';
        json["tuidan"] = '0';
        for (j = 0; j < material.length; j++) {
          if (material[j].material_no == json["material_no"]) {
            json["name"] = material[j].name;
            json["unit"] = material[j].unit;
            json["position"] = material[j].shelf_position;
            json["stock"] = dotFixed(material[j].stock);
            let yibei = parseFloat(json["yibei_shuliang"]);
            let stockTemp = parseFloat(json["stock"]);
            let quatity_total = parseFloat(json["quatity_total"]);
            if (isNaN(yibei))
              yibei = 0.0;
            if (isNaN(stockTemp))
              stockTemp = 0.0;
            //if( json["stock"] == '0' || json["stock"] == '' )
            if ((yibei + stockTemp) < quatity_total)
              json["beiliao_ztai"] = 3;
            break;
          }
        }
        if (j == material.length) // 没找到
        {
          json["name"] = "";
          json["unit"] = "";
          json["position"] = "";
          json["stock"] = '0';
          json["beiliao_ztai"] = 3;
        }
        if (json["beiliao_ztai"] == 3) {
          if (status == 0 || status == 3)
            array.push(json);
        }
        else if (status == 0 || json["beiliao_ztai"] == status) {
          array.push(json);
        }
        if (json["beiliao_ztai"] != suc4[i].beiliao_ztai) {
          sql = "update material_apply set beiliao_ztai = '" + json["beiliao_ztai"] + "' where id = '" + suc4[i].id + "'";
          await db_util.query(sql);
          console.log('物料表中预存的备料状态和实际状态不符：', suc4[i].beiliao_ztai, sql);
        }
      }
    }

    if (req.body.order != undefined) {
      let flag = false; // 升序
      if (req.body.order.indexOf('desc') > 0)
        flag = true;
      array.sort(keysort('position', flag));
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueyrMaterialSend error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//NOUSE
app.post('/QueryOrderStatus', async (req, res) => {
  try {
    var sql = "select id, beiliao_ztai from machining_sheet where quatity != '0' and union_order = '" + req.body.unionorder + "' and type_flag = 0";
    let suc = await db_util.query(sql);
    var flag = "True";
    for (var i = 0; i < suc.length; i++) {
      if (suc[i].beiliao_ztai != 2) {
        flag = "False";
        break;
      }
    }
    res.status(200);
    res.json({ "result": "ok", "order": flag });
  }
  catch (error) {
    console.log('QueyrOrderStatus error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/UpdateMaterialSend', async (req, res) => {
  let json = await UpdateMaterialSendEx(req.body);
  res.status(200);
  res.json(json);
})

async function UpdateMaterialSendEx(body, reject) // 拒绝时不再插入表material_send
{
  let sql = "";
  let json = { 'result': 'error' };
  console.log('UpdateMaterialSendEx', body);
  try {
    let id = 0;
    let where = "";
    let table_id = 0;
    let table_name = "";
    let yibei_shuliang = 0;
    let tuiku_shuliang = 0;
    if (body.list != undefined) // 批量设置箱号、领料人领料日期
    {
      try {
        let flag = false;
        let count = 0;
        for (let i = 0; i < body.list.length; i++) {
          id = parseInt(body.list[i]["id"]);
          if (isNaN(id))
            continue;
          if (id > 1800000000) {
            table_id = id - 1800000000;
            sql = "update material_apply set ";
          }
          else if (id > 500000000) {
            table_id = id - 500000000;
            sql = "update machining_sheet set ";
          }
          else {
            table_id = id;
            sql = "update dispatch_sheet set ";
          }
          where = " where id = '" + table_id + "'";

          flag = false;
          if (body.box != undefined) {
            if (flag)
              sql += ", ";
            sql += "box = '" + body.box + "'";
            flag = true;
          }
          if (body.lingliao_ren != undefined) {
            if (flag)
              sql += ", ";
            sql += "lingliao_ren = '" + body.lingliao_ren + "'";
            flag = true;
          }
          if (body.lingliao_riqi != undefined) {
            if (flag)
              sql += ", ";
            sql += "lingliao_riqi = '" + body.lingliao_riqi + "'";
            flag = true;
          }
          if (flag) {
            sql += where;
            let suc = await db_util.query(sql);
            if (suc.affectedRows > 0)
              count++;
            else
              console.log('Failed: ' + sql);
          }
        }
        console.log('UpdateMaterialSend批量处理：' + count);
        json['result'] = 'ok';
      }
      catch (error) {
        console.log('UpdateMaterialSendEx error: ' + error.message + ', SQL: ' + sql);
        json['description'] = error.message;
      }
      return json;
    }

    if (body.id == undefined) {
      if (body.unionorder == undefined) {
        res.status(200);
        res.json({ "result": "error", "description": "the id or unionorder is not found" });
        return;
      }
      where = " where union_order = '" + body.unionorder + "'";
    }
    else {
      //console.log('UpdateMeterialSend id = ' + body.id);
      id = parseInt(body.id); // 大于5亿：大表machining_sheet；大于18亿：物料申请表
      if (isNaN(id))
        id = 0;
      if (id > 1800000000)
        table_id = id - 1800000000;
      else if (id > 500000000)
        table_id = id - 500000000;
      else
        table_id = id;
      where = " where id = '" + table_id + "'";
    }
    let flag = false;
    if (id > 1800000000) {
      table_name = "material_apply";
      sql = "update material_apply set ";
    }
    else if (id > 500000000) {
      table_name = "machining_sheet";
      sql = "update machining_sheet set ";
    }
    else if (id > 0) {
      table_name = "dispatch_sheet";
      sql = "update dispatch_sheet set ";
      if (body.lingliao_ren != undefined) {
        if (flag)
          sql += ", ";
        sql += "lingliao_ren = '" + body.lingliao_ren + "'";
        flag = true;
      }
    }
    else // 传的是工联单号，修改所有标准件的领料时间
    {
      sql = "update machining_sheet set ";
      where = " where union_order = '" + body.unionorder + "' and type_flag = 0";
    }
    if (body.lingliao_ren != undefined) {
      if (flag)
        sql += ", ";
      sql += "lingliao_ren = '" + body.lingliao_ren + "'";
      flag = true;
    }
    if (body.lingliao_riqi != undefined) {
      if (flag)
        sql += ", ";
      sql += "lingliao_riqi = '" + body.lingliao_riqi + "'";
      flag = true;
    }
    if (body.lingliao_qixian != undefined) {
      if (flag)
        sql += ", ";
      sql += "lingliao_qixian = '" + body.lingliao_qixian + "'";
      flag = true;
    }
    if (body.lingliao_bzhu != undefined) {
      if (flag)
        sql += ", ";
      sql += "lingliao_bzhu = '" + body.lingliao_bzhu + "'";
      flag = true;
    }
    if (body.box != undefined) {
      if (flag)
        sql += ", ";
      sql += "box = '" + body.box + "'";
      flag = true;
    }
    if (body.yibei_shuliang != undefined) {
      if (flag)
        sql += ", ";
      sql += "yibei_shuliang = '" + body.yibei_shuliang + "'";
      flag = true;
      let sql2 = "select yibei_shuliang from ";
      sql2 += table_name;
      sql2 += where;
      let suc = await db_util.query(sql2);
      if (suc.length > 0) {
        yibei_shuliang = parseFloat(suc[0].yibei_shuliang);
        if (isNaN(yibei_shuliang))
          yibei_shuliang = 0;
      }
    }
    if (body.tuiku_shuliang != undefined) {
      if (flag)
        sql += ", ";
      sql += "tuiku_shuliang = '" + body.tuiku_shuliang + "'";
      flag = true;
      let sql2 = "select tuiku_shuliang from ";
      sql2 += table_name;
      sql2 += where;
      let suc = await db_util.query(sql2);
      if (suc.length > 0) {
        tuiku_shuliang = parseFloat(suc[0].tuiku_shuliang);
        if (isNaN(tuiku_shuliang))
          tuiku_shuliang = 0;
      }
    }
    if (body.beiliao_ztai != undefined) {
      if (flag)
        sql += ", ";
      sql += "beiliao_ztai = '" + body.beiliao_ztai + "'";
      flag = true;
    }
    if (flag) {
      sql += where;
      let sucData = await db_util.query(sql);
      console.log(sql);
      json["result"] = "ok";
      if (sucData.affectedRows > 0)
        json["description"] = "changedRows";
      else
        json["description"] = "not find the record";
      if (body.lingliao_riqi != undefined) {
        if (id > 1800000000) // 物料申请表中如果这个栏位有值就不再显示了
        {
          sql = "update material_apply set lingliao_riqi = '" + body.lingliao_riqi + "' where id = '" + table_id + "'";
          await db_util.query(sql);
        }
      }
      if (body.stock != undefined) {
        let material_no = "";
        let union_order = "";
        let sheet_order = "";
        let other_order = "";
        if (id > 1800000000) {
          sql = "select applyID, material_no, applyType, union_order from material_apply where id = '" + table_id + "'";
          let suc = await db_util.query(sql);
          if (suc.length > 0) {
            union_order = suc[0].applyID;
            material_no = suc[0].material_no;
            sheet_order = suc[0].applyType;
            other_order = suc[0].union_order;

            sql = "update material_apply set stock = '" + dotFixed(body.stock, 3) + "' where material_no = '" + material_no + "' and lingliao_riqi = ''";
            await db_util.query(sql);
            console.log(sql);
          }
        }
        else if (id > 500000000) {
          sql = "select union_order, sheet_order, material_no from machining_sheet where id = '" + table_id + "'";
          let suc = await db_util.query(sql);
          if (suc.length > 0) {
            union_order = suc[0].union_order;
            material_no = suc[0].material_no;
            sheet_order = suc[0].sheet_order;
          }
        }
        else {
          sql = "select union_order, ljmc, material_no from dispatch_sheet where id = '" + table_id + "'"
          let suc = await db_util.query(sql);
          if (suc.length > 0) {
            union_order = suc[0].union_order;
            sheet_order = suc[0].ljmc;
            material_no = suc[0].material_no;
          }
        }
        sql = "select stock from base_material where material_no = '" + material_no + "'";
        let suc = await db_util.query(sql);
        do {
          if (suc.length == 0)
            break;
          let stock = parseFloat(suc[0].stock); // 原来的库存
          if (isNaN(stock))
            stock = 0;
          /*if( stock <= 0 )
          {
            console.log('库房中料号' + material_no + '库存为0');
            break;
          }*/
          let stockTemp = parseFloat(body.stock); // 传入的是更新后的库存
          if (isNaN(stockTemp))
            stockTemp = 0;
          /*if( stockTemp <= 0 )
            break;
          if( stock < stockTemp )
          {
            console.log('库房中料号' + material_no + '库存为' + stock + '，不足以发放：' + stockTemp);
          }*/
          stock -= stockTemp; // stock如果小于0表示退库
          if (stock == 0)
            break;
          sql = "update base_material set stock = '" + dotFixed(stockTemp, 3) + "' where material_no = '" + material_no + "'";
          await db_util.query(sql);
          console.log(sql);

          let date = new Date();
          let timestamp = getMonthDayTime(date, 1, 1);
          if (body.yibei_shuliang != undefined) // 防止因退库数量减少导致库存减少引发发放物料的误判
          {
            stock = parseFloat(body.yibei_shuliang) - yibei_shuliang;
            if (stock > 0) // 已备数量增加
            {
              sql = "select id, quatity, price, manufacturer, usedQuatity from warehouse where material_no = '" + material_no + "'";
              let suc3 = await db_util.query(sql);
              for (let i = 0; i < suc3.length; i++) {
                let quatity = parseFloat(suc3[i].quatity);
                if (isNaN(quatity))
                  continue;
                let usedQuatity = parseFloat(suc3[i].usedQuatity);
                if (isNaN(usedQuatity))
                  usedQuatity = 0;
                if (usedQuatity >= quatity)
                  continue;
                let price = await GetPriceAfterTax(suc3[i].price, suc3[i].manufacturer);
                if ((quatity - usedQuatity) >= stock) {
                  sql = "insert into material_send values (null, '" + union_order + "', '" + sheet_order + "', '" + material_no + "', '" + dotFixed(stock, 3) + "', '" + price + "', '" + suc3[i].id + "', '" + timestamp + "', '" + other_order + "')";
                  await db_util.query(sql);
                  console.log('已备数量增加', sql);
                  usedQuatity += stock;
                  sql = "update warehouse set usedQuatity = '" + dotFixed(usedQuatity, 3) + "' where id = '" + suc3[i].id + "'";
                  await db_util.query(sql);
                  console.log('已备数量增加', sql);
                  break;
                }
                else {
                  let temp = quatity - usedQuatity;
                  sql = "insert into material_send values (null, '" + union_order + "', '" + sheet_order + "', '" + material_no + "', '" + dotFixed(temp, 3) + "', '" + price + "', '" + suc3[i].id + "', '" + timestamp + "', '" + other_order + "')";
                  await db_util.query(sql);
                  console.log('已备数量增加', sql);
                  stock -= temp;
                  sql = "update warehouse set usedQuatity = '" + dotFixed(quatity, 3) + "' where id = '" + suc3[i].id + "'";
                  await db_util.query(sql);
                  console.log('已备数量增加', sql);
                }
              }
            }
            else // 已备数量减少，修改以前插入的记录
            {
              stock = 0 - stock; // 改成正数
              sql = "select * from material_send where union_order = '" + union_order + "' and sheet_order = '" + sheet_order + "' and material_no = '" + material_no + "' and warehouse_id < 300000000 ORDER BY id DESC";
              let suc4 = await db_util.query(sql);
              for (let i = 0; i < suc4.length; i++) {
                let quatity = parseFloat(suc4[i].quatity);
                if (isNaN(quatity))
                  quatity = 0;
                if (quatity <= 0)
                  continue;
                if (quatity >= stock) {
                  let temp = quatity - stock;
                  sql = "update material_send set quatity = '" + dotFixed(temp, 3) + "' where id = '" + suc4[i].id + "'";
                  await db_util.query(sql);
                  console.log('已备数量减少，修改以前插入的记录', sql);
                  sql = "select * from warehouse where id = '" + suc4[i].warehouse_id + "'";
                  let suc5 = await db_util.query(sql);
                  if (suc5.length > 0) {
                    console.log(suc5[0]['material_no'], '已用数量111：', suc5[0].usedQuatity, quatity, stock);
                    let usedQuatity = parseFloat(suc5[0].usedQuatity);
                    if (isNaN(usedQuatity))
                      usedQuatity = 0;
                    if (usedQuatity >= stock) {
                      usedQuatity -= stock;
                      sql = "update warehouse set usedQuatity = '" + dotFixed(usedQuatity, 3) + "' where id = '" + suc5[0].id + "'";
                      await db_util.query(sql);
                      console.log('已备数量减少，修改以前插入的记录', sql);
                    }
                    else {
                      console.log('warehouse id = ' + suc4[i].warehouse_id + '已用数量竟然比退库数量少：' + suc5[0].usedQuatity + ' ~ ' + stock);
                      sql = "update warehouse set usedQuatity = '0' where id = '" + suc5[0].id + "'";
                      await db_util.query(sql);
                    }
                  }
                  break;
                }
                else {
                  sql = "update material_send set quatity = '0' where id = '" + suc4[i].id + "'";
                  await db_util.query(sql);
                  console.log('已备数量减少，修改以前插入的记录', sql);
                  sql = "select * from warehouse where id = '" + suc4[i].warehouse_id + "'";
                  let suc5 = await db_util.query(sql);
                  if (suc5.length > 0) {
                    console.log(suc5[0]['material_no'], '已用数量222：', suc5[0].usedQuatity, quatity, stock);
                    let usedQuatity = parseFloat(suc5[0].usedQuatity);
                    if (isNaN(usedQuatity))
                      usedQuatity = 0;
                    if (usedQuatity >= stock) {
                      usedQuatity -= stock;
                      sql = "update warehouse set usedQuatity = '" + dotFixed(usedQuatity, 3) + "' where id = '" + suc5[0].id + "'";
                      await db_util.query(sql);
                      console.log('已备数量减少，修改以前插入的记录', sql);
                    }
                    else {
                      sql = "update warehouse set usedQuatity = '0' where id = '" + suc5[0].id + "'";
                      await db_util.query(sql);
                      console.log('已备数量减少，修改以前插入的记录', sql);
                    }
                  }
                  stock -= quatity;
                }
              }
            }
          }
          else if (body.tuiku_shuliang != undefined) // 退库
          {
            stock = parseFloat(body.tuiku_shuliang) - tuiku_shuliang;
            if (stock > 0) // 退库数量增加了，要减少已用数量
            {
              sql = "select id, quatity, price, usedQuatity from warehouse where material_no = '" + material_no + "' ORDER BY id DESC";
              let suc3 = await db_util.query(sql);
              for (let i = 0; i < suc3.length; i++) {
                let id = 300000000 + suc3[i].id;
                sql = "select id, quatity, price from material_send where union_order = '" + union_order + "' and sheet_order = '" + sheet_order + "' and material_no = '" + material_no + "'";
                sql += " and (warehouse_id = '" + suc3[i]['id'] + "' OR warehouse_id = '" + id + "')";
                let suc4 = await db_util.query(sql);
                if (suc4.length == 0)
                  continue;
                let usedQuatity = parseFloat(suc3[i].usedQuatity);
                if (isNaN(usedQuatity))
                  usedQuatity = 0;
                if (usedQuatity <= 0)
                  continue;
                let quatity = 0;
                for (let k = 0; k < suc4.length; k++) {
                  let temp = parseFloat(suc4[k]['quatity']);
                  if (isNaN(temp))
                    temp = 0;
                  quatity += temp;
                }
                if (quatity < 0.0001) // 等于0
                  continue;
                if (quatity < usedQuatity) // 该料号同时被他人领用
                  usedQuatity = quatity;
                if (usedQuatity >= stock) {
                  let temp = parseFloat(suc3[i].usedQuatity) - stock;
                  sql = "update warehouse set usedQuatity = '" + dotFixed(temp, 3) + "' where id = '" + suc3[i].id + "'";
                  await db_util.query(sql);
                  console.log('退库处理，退库数量增加：' + sql);

                  if (reject == undefined) {
                    temp = 0 - stock;
                    sql = "insert into material_send values (null, '" + union_order + "', '" + sheet_order + "', '" + material_no + "', '" + dotFixed(temp, 3) + "', '" + suc4[0]['price'] + "', '" + id + "', '" + timestamp + "', '" + other_order + "')";
                    await db_util.query(sql);
                    console.log('退库处理，退库数量增加：' + sql);
                  }
                  else {
                    console.log('申请领料被拒绝，退库数量增加：', dotFixed(stock, 3));
                  }
                  break;
                }
                else {
                  let temp = parseFloat(suc3[i].usedQuatity) - usedQuatity;
                  sql = "update warehouse set usedQuatity = '" + dotFixed(temp, 3) + "' where id = '" + suc3[i].id + "'";
                  await db_util.query(sql);
                  stock -= usedQuatity;
                  console.log('退库处理，退库数量增加：' + sql);

                  if (reject == undefined) {
                    temp = 0 - usedQuatity;
                    sql = "insert into material_send values (null, '" + union_order + "', '" + sheet_order + "', '" + material_no + "', '" + dotFixed(temp, 3) + "', '" + suc4[0]['price'] + "', '" + id + "', '" + timestamp + "', '" + other_order + "')";
                    await db_util.query(sql);
                    console.log('退库处理，退库数量增加：' + sql);
                  }
                  else {
                    console.log('申请领料被拒绝，退库数量增加：', dotFixed(usedQuatity, 3));
                  }
                }
              }
            }
            else // 退库数量减少了，要增加已用数量
            {
              stock = 0 - stock; // 改成正数
              sql = "select id, quatity, price, manufacturer, usedQuatity from warehouse where material_no = '" + material_no + "'";
              let suc3 = await db_util.query(sql);
              for (let i = 0; i < suc3.length; i++) {
                let quatity = parseFloat(suc3[i].quatity);
                if (isNaN(quatity))
                  continue;
                let usedQuatity = parseFloat(suc3[i].usedQuatity);
                if (isNaN(usedQuatity))
                  usedQuatity = 0;
                if (usedQuatity >= quatity)
                  continue;
                let price = await GetPriceAfterTax(suc3[i].price, suc3[i].manufacturer);
                if ((quatity - usedQuatity) >= stock) {
                  usedQuatity += stock;
                  sql = "update warehouse set usedQuatity = '" + dotFixed(usedQuatity, 3) + "' where id = '" + suc3[i].id + "'";
                  await db_util.query(sql);
                  console.log('退库处理，退库数量减少：' + sql);

                  let id = suc3[i].id;
                  sql = "insert into material_send values (null, '" + union_order + "', '" + sheet_order + "', '" + material_no + "', '" + dotFixed(stock, 3) + "', '" + price + "', '" + id + "', '" + timestamp + "', '" + other_order + "')";
                  await db_util.query(sql);
                  console.log('退库处理，退库数量减少：' + sql);
                  break;
                }
                else {
                  sql = "update warehouse set usedQuatity = '" + dotFixed(quatity, 3) + "' where id = '" + suc3[i].id + "'";
                  await db_util.query(sql);
                  stock -= (quatity - usedQuatity);
                  console.log('退库处理，退库数量减少：' + sql);

                  let temp = quatity - usedQuatity;
                  let id = suc3[i].id;
                  sql = "insert into material_send values (null, '" + union_order + "', '" + sheet_order + "', '" + material_no + "', '" + dotFixed(temp, 3) + "', '" + price + "', '" + id + "', '" + timestamp + "', '" + other_order + "')";
                  await db_util.query(sql);
                  console.log('退库处理，退库数量减少：' + sql);
                }
              }
            }
          }
        } while (false);
      }
    }
    else {
      json['description'] = 'no column was matched to update';
      console.log('Failed: ' + sql);
    }
  }
  catch (error) {
    console.log('UpdateMaterialSendEx error: ' + error.message + ', SQL: ' + sql);
    json['description'] = error.message;
  }
  return json;
}

//FSMS
app.post('/QueryMaterialSendEx', async (req, res) => {
  try {
    let sql = "";
    let beiliao_ztai = 0;
    let i = 0, j = 0, k = 0;
    let array = new Array();
    let union_order = "";
    if (req.body.unionorder != undefined)
      union_order = req.body.unionorder;
    if (req.body.beiliao_ztai != undefined) {
      beiliao_ztai = parseInt(req.body.beiliao_ztai);
      if (isNaN(beiliao_ztai))
        beiliao_ztai = 0;
    }
    console.log('QueryMaterialSendEx ' + union_order + ' ' + beiliao_ztai);
    if (union_order.length == 0) {
      sql = "select union_order, name, quatity, delivery_date, charge_department, total_time from machining_union_sheet where status = 0 and length(engineer) > 0";
      let suc = await db_util.query(sql);
      for (i = 0; i < suc.length; i++) {
        j = 0;
        let queliao = 0;
        let yibeiliao = 0;
        let beiliaozhong = 0;
        // 所有工件都领料之后就不显示
        sql = "select * from machining_sheet where quatity != '0' and union_order = '" + suc[i].union_order + "' and type_flag = 0";
        let suc2 = await db_util.query(sql);
        for (k = 0; k < suc2.length; k++) {
          if (suc2[k].beiliao_ztai == 3)
            queliao++;
          else if (suc2[k].beiliao_ztai == 1)
            beiliaozhong++;
          else if (suc2[k].beiliao_ztai == 2) {
            yibeiliao++;
            if (suc2[k].lingliao_riqi == '') // 已备料但没有领料
              j++;
          }
        }
        sql = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and rawdata != 0";
        let suc3 = await db_util.query(sql);
        for (k = 0; k < suc3.length; k++) {
          if (suc3[k].beiliao_ztai == 3)
            queliao++;
          else if (suc3[k].beiliao_ztai == 1)
            beiliaozhong++;
          else if (suc3[k].beiliao_ztai == 2) {
            yibeiliao++;
            if (suc3[k].lingliao_riqi == '')
              j++;
          }
        }
        if (j == 0 && yibeiliao == (suc2.length + suc3.length)) // 都已领料
          continue;
        if (queliao > 0)
          j = 3;
        else if (yibeiliao == (suc2.length + suc3.length))
          j = 2;
        else
          j = 1;
        if (beiliao_ztai != 0 && beiliao_ztai != j)
          continue;
        let json = {};
        json["type_flag"] = 0;
        json["union_order"] = suc[i].union_order; // 工联单号
        json["delivery_date"] = suc[i].delivery_date; // 治具交期
        json["charge_department"] = suc[i].charge_department;// 付费部门
        json["name"] = suc[i].name; // 名称
        json["quatity"] = suc[i].quatity;
        json["total_time"] = suc[i].total_time;
        json["beiliao_ztai"] = j;
        array.push(json);
      }
      sql = "select * from material_apply";
      let suc4 = await db_util.query(sql);
      for (i = 0; i < suc4.length; i++) {
        if (suc4[i].beiliao_ztai == 2 && suc4[i].lingliao_riqi != '')
          continue;
        if (beiliao_ztai != 0 && beiliao_ztai != suc4[i].beiliao_ztai)
          continue;
        let json = {};
        json["type_flag"] = 3;
        json["union_order"] = suc4[i].applyID;
        json["delivery_date"] = "";
        if (suc4[i]['union_order'] != '') {
          sql = "select id, delivery_date from machining_union_sheet where union_order = '" + suc4[i]['union_order'] + "'";
          let suc2 = await db_util.query(sql);
          if (suc2.length > 0)
            json["delivery_date"] = suc2[0]['delivery_date'];
        }
        json["charge_department"] = suc4[i].charge_department;
        json["name"] = suc4[i].name;
        json["quatity"] = suc4[i].quatity;
        json["total_time"] = "";
        json["beiliao_ztai"] = suc4[i].beiliao_ztai;
        array.push(json);
      }
      res.status(200);
      res.json({ "result": "ok", "order": array });
      return;
    }
    //sql = "select * from base_material";
    //let material = await db_util.query(sql);
    sql = "select * from machining_union_sheet where union_order = '" + union_order + "'";
    let suc = await db_util.query(sql);
    sql = "select * from machining_sheet where quatity != '0' and union_order = '" + union_order + "'";
    let suc2 = await db_util.query(sql);
    sql = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + union_order + "' and rawdata != 0";
    let suc3 = await db_util.query(sql);
    i = 0;
    for (j = 0; j < suc3.length; j++) {
      if (beiliao_ztai != 0 && beiliao_ztai != suc3[j].beiliao_ztai)
        continue;
      let json = {};
      json["type_flag"] = 1;
      json["union_order"] = union_order; // 工联单号
      json["delivery_date"] = suc[i].delivery_date; // 治具交期
      json["charge_department"] = suc[i].charge_department;// 付费部门
      json["name"] = suc3[j].ljmc; // 名称
      json["quatity"] = suc3[j].gjsl;
      json["total_time"] = "";
      json["beiliao_ztai"] = suc3[j].beiliao_ztai;
      json["lingliao_riqi"] = suc3[j].lingliao_riqi;
      json["lingliao_qixian"] = suc3[j].lingliao_qixian;
      array.push(json);
    }
    // 加标准件
    for (k = 0; k < suc2.length; k++) {
      if (suc2[k].type_flag != '0')
        continue;
      if (beiliao_ztai != 0 && beiliao_ztai != suc2[k].beiliao_ztai)
        continue;
      let json = {};
      json["type_flag"] = 0;
      json["union_order"] = suc[i].union_order;
      json["delivery_date"] = suc[i].delivery_date;
      json["charge_department"] = suc[i].charge_department;
      json["name"] = suc2[k].sheet_order;
      json["quatity"] = suc2[k].quatity_total;
      json["total_time"] = suc2[k].speed_time;
      json["beiliao_ztai"] = suc2[k].beiliao_ztai;
      json["lingliao_riqi"] = suc2[k].lingliao_riqi;
      json["lingliao_qixian"] = suc2[k].lingliao_qixian;
      array.push(json);
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueyrMaterialSendEx error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryMaterialApply', async (req, res) => {
  try {
    let sql = "select * from material_apply";
    if (req.body.material_no != undefined)
      sql += " where material_no = '" + req.body.material_no + "'";
    else
      sql += " where lingliao_riqi = ''";
    let userInfo = CheckUserInfo(req);
    if (userInfo["isManager"] == false)
      sql += " and applicant = '" + userInfo["name"] + "'";
    let ret = await db_util.query(sql);
    let temp = 0.0;
    for (let i = 0; i < ret.length; i++) {
      temp = parseFloat(ret[i]['stock']);
      ret[i]['stock'] = dotFixed(temp, 3);
    }
    res.status(200);
    res.json({ "result": "ok", "order": ret });
  }
  catch (error) {
    console.log('QueryMaterialApply error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/AddMaterialApply', async (req, res) => {
  try {
    let body = req.body;
    // 准备好时间格式 年月日
    let date = new Date();
    let day = "" + date.getFullYear();
    if (date.getMonth() < 9)
      day += '0';
    day += (date.getMonth() + 1);
    if (date.getDate() < 10)
      day += '0';
    day += date.getDate();
    let days = day + "%";
    // 找到day这个时间的applyId并++，然后用day拼接applyId
    let sql = "select applyID from material_apply where applyID like '" + days + "' order by applyID desc limit 1";
    let ret = await db_util.query(sql);
    if (ret.length > 0) {
      let id = parseInt(ret[0].applyID.substr(8));
      if (isNaN(id))
        id = 0;
      id++;
      if (id < 10)
        day += '000';
      else if (id < 100)
        day += '00';
      else if (id < 1000)
        day += '0';
      day += id;
    }
    else {
      day += '0001';
    }
    // 获取传递过来的工单，最后整合所有参数插入到 material_apply 表中
    let union_order = "";
    if (body.union_order != undefined)
      union_order = body.union_order;
    if (union_order != '') {
      sql = "select status from machining_union_sheet where union_order = '" + union_order + "'";
      let suc = await db_util.query(sql);
      if (suc.length == 0) {
        res.status(200);
        res.json({ "result": "error", "description": "該工單號不存在" });
        return;
      }
      if (suc[0]['status'] == 2) {
        res.status(200);
        res.json({ "result": "error", "description": "該工單號已被取消" });
        return;
      }
    }
    sql = "insert into material_apply values(null, '" + day + "', '" + body.material_no + "', '" + body.name + "', '" + body.unit + "', '" + body.stock + "', '" + body.applyType + "', '" + body.charge_department + "', '" + body.applicant + "', '" + body.quatity + "', '', '" + body.remark + "', '', '', '', 1, '', '', '" + union_order + "')";
    await db_util.query(sql);
    res.status(200);
    res.json({ "result": "ok", "ID": day });
  }
  catch (error) {
    console.log('AddMaterialApply error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/BatchAddMaterialApply', async (req, res) => {
  try {
    let totalDays = [];
    let values = [];
    let todayFirstId, id,tempId, index// 用于获取最新的id
    
    // 准备好当天 时间:年月日
    let date = new Date();
    let day = "" + date.getFullYear();
    if (date.getMonth() < 9)
      day += '0';
    day += (date.getMonth() + 1);
    if (date.getDate() < 10)
      day += '0';
    day += date.getDate();
    let days = day + "%";
    // 找到day这个时间的applyId并++，然后用day拼接applyId
    let sqlSelect = "SELECT applyID FROM material_apply WHERE applyID LIKE ? ORDER BY applyID DESC LIMIT 1";
    let ret = await db_util.query(sqlSelect, [days]);

    // 调用一次函数，day和appid是固定的，因此上面两部分代码不放入循环中
    
    // 下面循环是为了把上传的每一条数据整合好放入values数组，最后只要执行一次insert，提高了性能
    for (let i = 0; i < req.body.length; i++) {
      let body = req.body[i];
      let dayTemp = day;

      if (ret.length > 0) {// 当天不止第一次批量添加
        let applyId = parseInt(ret[0].applyID.substr(8));
        if (isNaN(applyId))
          id = 0;
        if (i == 0) id = ++applyId;// 第一条数据：获取数据库中最大id++
        else {// >1 条数据时，获取上一次Id的第一个非0的数字++，再把0补回去
          tempId = values[i - 1][1].substr(8);
          index = tempId.indexOf(tempId.match(/[^0]/));
          id =  parseInt(tempId.substr(index))+ 1;
        } 
        if (id < 10)
          dayTemp += '000';
        else if (id < 100)
          dayTemp += '00';
        else if (id < 1000)
          dayTemp += '0';
        dayTemp += id;
      }// 当天第一次批量添加
      else {// 第一条数据，day='0001'
        if (i == 0) {
          todayFirstId = '0001';
          dayTemp += todayFirstId;
        } else {// >1条数据时，获取上一次Id的第一个非0的数字++，再把0补回去
          tempId = values[i - 1][1].substr(8);
          index = tempId.indexOf(tempId.match(/[^0]/));
          todayFirstId = parseInt(tempId.substr(index)) + 1;
          if (todayFirstId < 10)
            dayTemp += '000';
          else if (todayFirstId < 100)
            dayTemp += '00';
          else if (todayFirstId < 1000)
            dayTemp += '0';
          dayTemp += todayFirstId;
        }
      }

      // 获取传递过来的工单，并判断是否非法
      let union_order = "";
      if (body.union_order != undefined)
        union_order = body.union_order;
      if (union_order != '') {
        sql = "SELECT status FROM machining_union_sheet WHERE union_order = ?";
        let suc = await db_util.query(sql, [union_order]);
        if (suc.length == 0) {
          res.status(200);
          res.json({ "result": "error", "description": "第"+(i+1)+"行数据的工單號不存在！" });
          return;
        }
        if (suc[0]['status'] == 2) {
          res.status(200);
          res.json({ "result": "error", "description": "第"+(i+1)+"行数据的工單號已被取消！" });
          return;
        }
      }

      // 将参数值添加到数组中
      values.push([null, dayTemp, body.material_no, body.name, body.unit, body.stock, body.applyType, body.charge_department, body.applicant, body.quatity, '', body.remark, '', '', '', 1, '', '', union_order]);
      totalDays.push(dayTemp);
    }

    // 执行批量插入语句，放在外面提高性能
    let sqlInsert = "INSERT INTO material_apply VALUES ?";
    // 将整合好的values插入到 material_apply 表中
    await db_util.query(sqlInsert, [values]);

    res.status(200);
    res.json({ "result": "ok", "ID": totalDays });
  } catch (error) {
    console.log('BatchAddMaterialApply error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
});

//FSMS
app.post('/UpdateMaterialApply', async (req, res) => {
  try {
    let body = req.body;
    let id = parseInt(body.id);
    let sql = "select * from material_apply where id = '" + id + "'";
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      res.status(200);
      res.json({ "result": "error", "description": "not set id" });
      return;
    }
    /*if( suc[0].checker != '' )
    {
      res.status(200);
      res.json({"result":"error", "description":"该记录已核签，不能再修改！"});
      return;
    }*/
    let union_order = "";
    if (body.union_order != undefined)
      union_order = body.union_order;
    if (union_order != '') {
      sql = "select status from machining_union_sheet where union_order = '" + union_order + "'";
      let suc2 = await db_util.query(sql);
      if (suc2.length == 0) {
        res.status(200);
        res.json({ "result": "error", "description": "該工單號不存在" });
        return;
      }
      if (suc2[0]['status'] == 2) {
        res.status(200);
        res.json({ "result": "error", "description": "該工單號已被取消" });
        return;
      }
    }
    sql = "select column_name from information_schema.COLUMNS where table_schema = '" + db_util.config.db_name + "' and table_name = 'material_apply' ORDER BY ordinal_position ASC";
    let suc3 = await db_util.query(sql);
    let flag = false;
    sql = "update material_apply set ";
    for (let i = 7; i < suc3.length; i++) // 去掉id、applyID、material_no、name、unit、stock、applyType
    {
      if (suc3[i].column_name == 'lingliao_riqi')
        continue;
      else if (suc3[i].column_name == 'lingliao_ren')
        continue;
      if (body[suc3[i].column_name] != undefined) {
        if (flag)
          sql += ", ";
        sql += suc3[i].column_name;
        sql += " = \'";
        sql += body[suc3[i].column_name];
        sql += '\'';
        flag = true;

        if (suc3[i].column_name == 'status') // status的值可能是""或true/false
        {
          if ('boolean' == typeof body[suc3[i].column_name]) {
            if (body[suc3[i].column_name] == false && suc[0]['yibei_shuliang'] != '') // 被拒绝，已备数量、退库数量都清空
            {
              let yibei_shuliang = parseFloat(suc[0]['yibei_shuliang']);
              if (suc[0]['tuiku_shuliang'] != '') {
                let tuiku_shuliang = parseFloat(suc[0]['tuiku_shuliang']);
                if (isNaN(tuiku_shuliang))
                  tuiku_shuliang = 0;
                yibei_shuliang -= tuiku_shuliang;
              }
              let stock = parseFloat(suc[0]['stock']);
              stock += yibei_shuliang;
              yibei_shuliang = parseFloat(suc[0]['yibei_shuliang']);
              let body = {};
              body['id'] = 1800000000 + id;
              body['tuiku_shuliang'] = dotFixed(yibei_shuliang, 3);
              body['stock'] = dotFixed(stock, 3);
              await UpdateMaterialSendEx(body, body['tuiku_shuliang']);
              let sql2 = "delete from material_send where union_order = '" + suc[0]['applyID'] + "'";
              await db_util.query(sql2);
              console.log(sql2);

              sql += ", yibei_shuliang = '0', tuiku_shuliang = '0', beiliao_ztai = ";
              yibei_shuliang = parseFloat(suc[0]['quatity']);
              if (yibei_shuliang > stock)
                sql += '3';
              else
                sql += '1';
            }
          }
        }
      }
    }
    if (flag) {
      sql += " where id = '" + id + "'";
      let sucData = await db_util.query(sql);
      let json = {};
      json["result"] = "ok";
      if (sucData.affectedRows > 0) {
        console.log('OK', sql);
        json["description"] = "changedRows";
      }
      else {
        console.log('Failed:', sql);
        json["description"] = "not find the record";
      }
      res.status(200);
      res.json(json);
    }
    else {
      res.status(200);
      res.json({ "result": "error", "description": "no column was matched to update" });
      console.log('Failed: ' + sql);
    }
  }
  catch (error) {
    console.log('UpdateMaterialApply error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/DeleteMaterialApply', async (req, res) => {
  try {
    let body = req.body;
    if (body.id == undefined) {
      res.status(200);
      res.json({ "result": "error", "description": "not set id" });
      return;
    }
    let sql = "select * from material_apply where id = '" + body.id + "'";
    let suc = await db_util.query(sql);
    if (suc.length > 0) {
      if (suc[0]["status"] == 'true') {
        res.status(200);
        res.json({ "result": "error", "description": "已签核的记录不能删除！" });
        return;
      }
    }
    sql = "delete from material_apply where id = '" + body.id + "'";
    let sucData = await db_util.query(sql);
    let json = {};
    if (sucData.affectedRows > 0) {
      json["result"] = "ok";
      json["description"] = "changedRows";
    }
    else {
      json["result"] = "error";
      json["description"] = "not find the record";
    }
    res.status(200);
    res.json(json);
  }
  catch (error) {
    console.log('DeleteMaterialApply error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/UpdateWarehouse', async (req, res) => {
  try {
    var body = req.body;
    if (body.id == undefined) {
      res.status(200);
      res.json({ "result": "error", "description": "not set id" });
      return;
    }
    var flag = false;
    var sql = "select material_no, quatity from warehouse where id = '" + body.id + "'";
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      res.status(200);
      res.json({ "result": "error", "description": "the id does not exist" });
      return;

    }
    sql = "Update warehouse set ";
    if (body.PR_NO != undefined) {
      if (flag)
        sql += ", ";
      sql += "PR_NO = '" + body.PR_NO + "'";
      flag = true;
    }
    if (body.PO_NO != undefined) {
      if (flag)
        sql += ", ";
      sql += "PO_NO = '" + body.PO_NO + "'";
      flag = true;
    }
    if (body.SN != undefined) {
      if (flag)
        sql += ", ";
      sql += "SN = '" + body.SN + "'";
      flag = true;
    }
    if (body.material_no != undefined) {
      if (flag)
        sql += ", ";
      sql += "material_no = '" + body.material_no + "'";
      flag = true;
    }
    if (body.quatity != undefined) {
      if (flag)
        sql += ", ";
      sql += "quatity = '" + body.quatity + "'";
      flag = true;
    }
    if (body.price != undefined) {
      if (flag)
        sql += ", ";
      sql += "price = '" + body.price + "'";
      flag = true;
    }
    if (body.manufacturer != undefined) {
      if (flag)
        sql += ", ";
      sql += "manufacturer = '" + body.manufacturer + "'";
      flag = true;
    }
    if (body.currency != undefined) {
      if (flag)
        sql += ", ";
      sql += "currency = '" + body.currency + "'";
      flag = true;
    }
    if (body.check_no != undefined) {
      if (flag)
        sql += ", ";
      sql += "check_no = '" + body.check_no + "'";
      flag = true;
    }
    if (body.reason != undefined) {
      if (flag)
        sql += ", ";
      sql += "purchasing_reason = '" + body.purchasing_reason + "'";
      flag = true;
    }
    if (flag) {
      sql += " where id = '" + body.id + "'";
      let sucData = await db_util.query(sql);
      var json = {};
      json["result"] = "ok";
      if (sucData.affectedRows > 0)
        json["description"] = "changedRows";
      else
        json["description"] = "not find the record";
      if (body.material_no != undefined && body.material_no != suc[0].material_no) {
        // 旧料号的库存需要减掉
        sql = "select stock from base_material where material_no = '" + suc[0].material_no + "'";
        let suc2 = await db_util.query(sql);
        if (suc2.length > 0) {
          var stock = parseFloat(suc2[0].stock) - parseFloat(suc[0].quatity);
          sql = "update base_material set stock = '" + dotFixed(stock, 3) + "' where material_no = '" + suc[0].material_no + "'";
          await db_util.query(sql);
        }
        // 新料号的库存需要增加
        sql = "select stock from base_material where material_no = '" + body.material_no + "'";
        let suc3 = await db_util.query(sql);
        if (suc3.length > 0) {
          var stock = parseFloat(suc3[0].stock);
          if (body.quatity != undefined)
            stock += parseFloat(body.quatity);
          else
            stock += parseFloat(suc[0].quatity);
          sql = "update base_material set stock = '" + dotFixed(stock, 3) + "' where material_no = '" + body.material_no + "'";
          await db_util.query(sql);
        }
      }
      else if (body.quatity != undefined && body.quatity != suc[0].quatity) {
        sql = "select stock from base_material where material_no = '" + suc[0].material_no + "'";
        let suc4 = await db_util.query(sql);
        if (suc4.length > 0) {
          var stock = parseFloat(suc4[0].stock) - parseFloat(suc[0].quatity) + parseFloat(body.quatity);
          sql = "update base_material set stock = '" + dotFixed(stock, 3) + "' where material_no = '" + suc[0].material_no + "'";
          await db_util.query(sql);
        }
      }
      res.status(200);
      res.json(json);
    }
    else {
      res.status(200);
      res.json({ "result": "error", "description": "no column was matched to update" });
      console.log('Failed: ' + sql);
    }
  }
  catch (error) {
    console.log('UpdateWarehouse error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/AddDownloadCount', async (req, res) => {
  try {
    var sql = "";
    var download_count = 1;
    let ret = await db_util.query("select * from cncother where name = 'downloadcount'");
    if (ret.length > 0) {
      var count = parseInt(ret[0].value);
      if (isNaN(count))
        count = 0;
      download_count += count;
    }
    if (ret.length == 0)
      sql = "insert into cncother (name, value) values('downloadcount', '" + download_count + "')";
    else
      sql = "update cncother set value = '" + download_count + "' where name = 'downloadcount'";
    await db_util.query(sql);
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('AddDownloadCount error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})
// 总检报表 FSMS
app.post('/QueryBaobiaoZongjian', async (req, res) => {
  try {
    let sql = "select * from machining_union_sheet where songjian_time != ''";
    let starttime = 0;
    let date = new Date();
    setTime(date, 23, 59, 59, 0);
    let endtime = date.getTime();
    if (req.body.endtime != undefined && req.body.endtime != "")
      endtime = Date.parse(req.body.endtime);
    if (req.body.starttime != undefined && req.body.starttime != "")
      starttime = Date.parse(req.body.starttime);
    else {
      let days = getDaysOfMonth(date.getMonth(), date.getFullYear()) - 1;
      starttime = endtime - days * 24 * 3600 * 1000;
    }
    if ((endtime - starttime) > (90 * 24 * 3600 * 1000)) {
      starttime = endtime - 90 * 24 * 3600 * 1000;
    }
    date.setTime(starttime);
    setTime(date, 0, 0, 0, 0);
    starttime = date.getTime();
    let suc = await db_util.query(sql);
    let array = new Array();
    let list = new Array();
    let i, k, songjian_time = 0;
    let riqi = "";
    let ok_count, ng_count;
    i = starttime;
    while (i <= endtime) {
      date.setTime(i);
      let json = {};
      json["day"] = getMonthDayTime(date, 1);
      json["ng"] = 0;
      json["ok"] = 0;
      array.push(json);
      i += 24 * 3600 * 1000;
    }
    date.setTime(starttime);
    sql = getMonthDayTime(date, 1);
    date.setTime(endtime);
    for (i = 0; i < suc.length; i++) {
      songjian_time = Date.parse(suc[i].songjian_time);
      if (isNaN(songjian_time))
        songjian_time = 0;
      if (songjian_time < starttime || songjian_time >= endtime)
        continue;
      date.setTime(songjian_time);
      riqi = getMonthDayTime(date, 1);
      ng_count = parseInt(suc[i].zongjian_ng_count);
      if (isNaN(ng_count))
        ng_count = 0;
      ok_count = parseInt(suc[i].zongjian_ok_count);
      if (isNaN(ok_count))
        ok_count = 0;
      for (k = 0; k < array.length; k++) {
        if (array[k]["day"] == riqi) {
          array[k]["ng"] += ng_count;
          array[k]["ok"] += ok_count;
          break;
        }
      }

      let json = {};
      json["unionorder"] = suc[i]["union_order"];
      json["name"] = suc[i]["name"];
      json["quatity"] = suc[i]["quatity"];
      json["code19"] = suc[i]["code19"];
      json["tips"] = "";
      json["songjian_time"] = suc[i]["songjian_time"];
      json["ok_count"] = suc[i]["zongjian_ok_count"];
      json["ng_count"] = suc[i]["zongjian_ng_count"];
      json["worktime"] = suc[i]["zongjian_shijian"];
      json["jiaoqi"] = suc[i]["delivery_date"];
      json["remark"] = suc[i]["zongjian_beizhu"];
      if (ng_count > 0)
        json["tips"] = "已品檢/NG";
      else if (ok_count > 0)
        json["tips"] = "已品檢";
      list.push(json);
    }
    res.status(200);
    res.json({ "result": "ok", "order": array, "list": list });
  }
  catch (error) {
    console.log('QueryBaobiaoZongjian error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})
// 品检报表 FSMS
app.post('/QueryBaobiaoPinjian', async (req, res) => {
  try {
    let sql = "select * from dispatch_sheet where gjsl != '0' and songjian_shijian != '' and rawdata != 0";
    let starttime = 0;
    let date = new Date();
    setTime(date, 23, 59, 59, 0);
    let endtime = date.getTime();
    if (req.body.endtime != undefined)
      endtime = Date.parse(req.body.endtime);
    if (req.body.starttime != undefined)
      starttime = Date.parse(req.body.starttime);
    else {
      let days = getDaysOfMonth(date.getMonth(), date.getFullYear()) - 1;
      starttime = endtime - days * 24 * 3600 * 1000;
    }
    if ((endtime - starttime) > (90 * 24 * 3600 * 1000)) {
      starttime = endtime - 90 * 24 * 3600 * 1000;
    }
    let suc = await db_util.query(sql);
    let array = new Array();
    let list = new Array();
    let i, k, songjian_shijian = 0;
    let riqi = "";
    let ok_count, ng_count;
    i = starttime;
    while (i <= endtime) {
      date.setTime(i);
      let json = {};
      json["day"] = getMonthDayTime(date, 1);
      json["ng"] = 0;
      json["ok"] = 0;
      array.push(json);
      i += 24 * 3600 * 1000;
    }
    date.setTime(starttime);
    sql = getMonthDayTime(date, 1);
    date.setTime(endtime);
    console.log('品检报表下载：' + sql + ' ~ ' + getMonthDayTime(date, 1));
    for (i = 0; i < suc.length; i++) {
      songjian_shijian = Date.parse(suc[i].songjian_shijian);
      if (isNaN(songjian_shijian))
        songjian_shijian = 0;
      if (songjian_shijian < starttime || songjian_shijian >= endtime)
        continue;
      k = suc[i].gjjcjg.indexOf(',');
      if (k < 0)
        continue;
      if (k == 0)
        ng_count = 0;
      else {
        riqi = suc[i].gjjcjg.slice(0, k); // NG
        ng_count = parseInt(riqi);
        if (isNaN(ng_count))
          ng_count = 0;
      }
      riqi = suc[i].gjjcjg.slice(k + 1); // OK
      ok_count = parseInt(riqi);
      if (isNaN(ok_count))
        ok_count = 0;
      date.setTime(songjian_shijian);
      riqi = getMonthDayTime(date, 1);
      for (k = 0; k < array.length; k++) {
        if (array[k]["day"] == riqi) {
          array[k]["ng"] += ng_count;
          array[k]["ok"] += ok_count;
          break;
        }
      }

      let json = {};
      json["unionorder"] = suc[i]["union_order"];
      json["name"] = suc[i]["name"];
      json["box"] = suc[i]["box"];
      //json["tips"] = "";
      json["songjian_time"] = suc[i]["songjian_shijian"];
      json["worktime"] = "";
      json["ng_count"] = ng_count;
      json["ok_count"] = ok_count;
      json["remark"] = suc[i]["pinjian_bzhu"];
      json["jiaoqi"] = "";
      /*if( ng_count > 0 )
        json["tips"] = "已品檢/NG";
      else if( ok_count > 0 )
        json["tips"] = "已品檢";*/
      sql = "select * from machining_union_sheet where union_order = '" + suc[i]["union_order"] + "'";
      let succ2 = await db_util.query(sql);
      if (succ2.length > 0) {
        json["worktime"] = succ2[0].pinjian_shijian;
        json["jiaoqi"] = succ2[0].delivery_date;
      }
      list.push(json);
    }
    res.status(200);
    res.json({ "result": "ok", "order": array, "list": list });
  }
  catch (error) {
    console.log('QueryBaobiaoPinjian error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

async function GetPriceAfterTax(price, manufacturer, precision) // precision: 精度，小数点后面有几位小数
{
  if (price == 0)
    return 0;
  let priceAfterTax = 0.0;
  if ("string" == typeof price)
    priceAfterTax = parseFloat(price);
  else
    priceAfterTax = price;
  let rate = 0.13;
  let sql = "select * from firm_info where fullname = '" + manufacturer + "'";
  let suc = await db_util.query(sql);
  if (suc.length > 0) {
    rate = parseFloat(suc[0].tax_rate);
    if (isNaN(rate))
      rate = 0.13;
  }
  priceAfterTax /= (1 + rate);
  sql = priceAfterTax.toString();
  let length = 3;
  if (precision != undefined) {
    length = parseInt(precision);
    if (isNaN(length))
      length = 3;
  }
  if (sql.indexOf('.') > 0 && sql.split('.')[1].length > length)
    priceAfterTax = priceAfterTax.toFixed(length);
  if ("string" == typeof priceAfterTax)
    return parseFloat(priceAfterTax);
  return priceAfterTax;
}

async function GetLingquCount(unionorder) {
  let count = 0;
  try {
    let i, k;
    let sql = "select * from delivery_sheet where union_order = '" + unionorder + "' and starttime != ''";
    let suc = await db_util.query(sql);
    for (i = 0; i < suc.length; i++) {
      k = parseInt(suc[i].quatity);
      if (isNaN(k))
        k = 0;
      count += k;
    }
  }
  catch (error) {
    console.log('GetLingquCount: ' + error.message);
  }
  return count;
}

// 人工工时比例报表 FSMS
app.post('/QueryBaobiaoGongshi', async (req, res) => {
  try {
    let sql = "select * from delivery_sheet where starttime != '' GROUP BY union_order ORDER BY starttime ASC";
    let starttime = 0;
    let endtime = Date.now();
    if (req.body.starttime != undefined)
      starttime = Date.parse(req.body.starttime);
    if (req.body.endtime != undefined)
      endtime = Date.parse(req.body.endtime);
    let succ2 = await db_util.query(sql);
    let array = new Array();
    let i, j, k, lingqu_time = 0;
    let quatity, price;
    let date = new Date();
    for (j = 0; j < succ2.length; j++) {
      sql = "select * from machining_union_sheet where union_order = '" + succ2[j].union_order + "'";
      let suc = await db_util.query(sql);
      if (suc.length == 0)
        continue;
      lingqu_time = Date.parse(suc[0].lingqu_time);
      if (isNaN(lingqu_time))
        continue;
      if (lingqu_time < starttime || lingqu_time >= endtime)
        continue;
      // 看是否已全部领取
      i = await GetLingquCount(suc[0].union_order); // 已领取
      k = parseInt(suc[0].quatity); // 总数
      if (i < k) {
        console.log('人工工时报表：未全部领取，总表ID：' + suc[0].id + '，数量：' + k + '，已领取：' + i);
        continue;
      }
      date.setTime(lingqu_time);
      i = 0;
      let json = {};
      json["date"] = getMonthDayTime(date, 1);
      json["union_order"] = suc[i].union_order;
      json["name"] = suc[i].name;
      json["quatity"] = parseFloat(suc[i].quatity);
      json["apply_person"] = suc[i].apply_person;
      if (suc[i].factory == undefined)
        json["factory"] = "";
      else
        json["factory"] = suc[i].factory;
      json["charge_department"] = suc[i].charge_department;
      json["total_time"] = suc[i].total_time;
      json["cost"] = 0.0; // 材料费用
      sql = "select id, quatity, price from material_send where union_order = '" + suc[i].union_order + "' OR other_order = '" + suc[i].union_order + "'";
      let suc2 = await db_util.query(sql);
      for (k = 0; k < suc2.length; k++) {
        quatity = parseFloat(suc2[k].quatity);
        if (isNaN(quatity))
          quatity = 0;
        price = parseFloat(suc2[k].price);
        if (isNaN(price))
          price = 0.0;
        json["cost"] += quatity * price;
      }
      json["price"] = suc[i].price;
      price = parseFloat(suc[i].price);
      if (isNaN(price))
        price = 0.0;
      quatity = parseFloat(suc[i].quatity);
      if (isNaN(quatity))
        quatity = 0.0;
      json["total_price"] = dotFixed(quatity * price);
      json["cost"] = dotFixed(json["cost"]);
      array.push(json);
    }
    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryBaobiaoGongshi error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})
// Delay原因分析报表
function parseDelayRemark(time, remark, array) {
  if (remark == null || time == null)
    return 0;
  if (remark.length == 0 || time.length == 0)
    return 0;
  console.log('Delay原因分析: ' + time + ', ' + remark);
  var date = new Date(time);
  var month = getMonthDayTime(date);
  var month_name = ['JAN.', 'FEB.', 'MAR.', 'APR.', 'MAY.', 'JUN.', 'JUL.', 'AUG.', 'SEP.', 'OCT.', 'NOV.', 'DEC.'];
  var arr = new Array();
  var index = remark.indexOf(',');
  if (index < 0) {
    arr.push(remark);
  }
  else {
    var temp = "";
    var offset = 0;
    while (index >= offset) {
      if (index > offset) {
        temp = remark.slice(offset, index);
        arr.push(temp);
      }
      offset = index + 1;
      index = remark.indexOf(',', offset);
      if (index < 0) {
        temp = remark.slice(offset);
        if (temp.length > 0)
          arr.push(temp);
        break;
      }
    }
  }
  var flag = true;
  var j = 0, k = 0, i = 0;
  for (k = 0; k < arr.length; k++) {
    for (j = 0; j < array.length; j++) {
      if (array[j].month == month) {
        for (i = 0; i < array[j]["data"].length; i++) {
          if (array[j]["data"][i].name == arr[k]) {
            array[j]["data"][i].count++;
            flag = false;
            break;
          }
        }
      }
    }
    if (flag) {
      for (j = 0; j < array.length; j++) {
        if (array[j].month == month) {
          for (i = 0; i < array[j]["data"].length; i++) {
            if (array[j]["data"][i].name == arr[k]) {
              array[j]["data"][i].count++;
              flag = false;
              break;
            }
          }
          if (flag) {
            var json2 = {};
            json2["name"] = arr[k];
            json2["count"] = 1;
            json2["ratio"] = "";
            array[j]["data"].push(json2);
          }
          break;
        }
      }
      if (j == array.length) {
        var json = {};
        json["month"] = month;
        json["month_name"] = month_name[date.getMonth()];
        json["data"] = new Array();
        var json2 = {};
        json2["name"] = arr[k];
        json2["count"] = 1;
        json2["ratio"] = "";
        json["data"].push(json2);
        array.push(json);
      }
    }
  }
  return k;
}

//FSMS
app.post('/QueryBaobiaoDelay', async (req, res) => {
  try {
    let sql = "select * from machining_union_sheet where status != 2 and lingqu_time != ''";
    let starttime = 0;
    let endtime = Date.now();
    if (req.body.endtime != undefined)
      endtime = Date.parse(req.body.endtime);
    let suc = await db_util.query(sql);
    let array = new Array();
    let list = new Array();
    let i, j, k, time = 0;
    let date = new Date();
    i = date.getFullYear() - 1;
    date.setFullYear(i, 11, 21); // 从上一年的12月21日开始
    starttime = date.getTime();
    if (req.body.starttime != undefined) {
      starttime = Date.parse(req.body.starttime);
      if (isNaN(starttime))
        starttime = date.getTime();
    }
    date.setTime(starttime);
    let month_name = ['JAN.', 'FEB.', 'MAR.', 'APR.', 'MAY.', 'JUN.', 'JUL.', 'AUG.', 'SEP.', 'OCT.', 'NOV.', 'DEC.'];
    for (i = 0; i < 12; i++) {
      let json = {};
      json["month"] = getMonthDayTime(date);
      k = date.getMonth();
      json["month_name"] = month_name[k];
      json["data"] = new Array();
      array.push(json);
      if (k < 11) {
        k++;
        date.setMonth(k);
      }
      else {
        date.setFullYear(date.getFullYear() + 1);
        date.setMonth(0);
      }
    }
    for (i = 0; i < suc.length; i++) {
      time = Date.parse(suc[i].lingqu_time);
      if (isNaN(time))
        time = 0;
      if (time < starttime || time >= endtime)
        continue;
      // 看是否已全部领取
      j = await GetLingquCount(suc[i].union_order); // 已领取
      k = parseInt(suc[i].quatity); // 总数
      if (j < k) {
        console.log('Delay原因分析报表：未全部领取，总表ID：' + suc[0].id + '，数量：' + k + '，已领取：' + j);
        continue;
      }
      date.setTime(time);
      time = 0;
      time += parseDelayRemark(suc[i].design_end_date, suc[i].design_remark, array);
      time += parseDelayRemark(suc[i].assemble_end_date, suc[i].assemble_remark, array);

      sql = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and rawdata != 0";
      let succ2 = await db_util.query(sql);
      let jiagong = "";
      let ercijg = "";
      for (k = 0; k < succ2.length; k++) {
        //time += parseDelayRemark(succ2[k].code_end_date, succ2[k].code_remark, array);
        time += parseDelayRemark(succ2[k].end_date, succ2[k].machine_remark, array);
        time += parseDelayRemark(succ2[k].machine_end_date_2, succ2[k].machine_remark_2, array);

        if (succ2[k].end_date != '' && succ2[k].machine_remark != '') {
          if (jiagong.length > 0)
            jiagong += ";";
          jiagong += succ2[k].machine_remark;
        }
        if (succ2[k].machine_end_date_2 != '' && succ2[k].machine_remark_2 != '') {
          if (ercijg.length > 0)
            ercijg += ";";
          ercijg += succ2[k].machine_remark_2;
        }
      }

      if (time == 0)
        continue;
      console.log('Delay ' + suc[i].union_order + ', ' + time + ' items, p79_id: ' + suc[i].p79_id);

      sql = "select * from p79_tofsms where id = '" + suc[i].p79_id + "'";
      let succ3 = await db_util.query(sql);
      if (succ3.length > 0) {
        let json = {};
        json["apply_date"] = succ3[0].ApplyDateTime.substr(0, 10);
        json["delivery_date"] = suc[i].delivery_date;
        json["apply_person"] = suc[i].apply_person;
        json["charge_department"] = suc[i].charge_department;
        json["unionorder"] = suc[i].union_order;
        json["sheji"] = suc[i].design_remark;
        json["jiagong"] = jiagong;
        json["ercijiagong"] = ercijg;
        json["zuzhuang"] = suc[i].assemble_remark;
        list.push(json);
      }
    }
    for (i = 0; i < array.length; i++) {
      time = 0;
      for (k = 0; k < array[i].data.length; k++) {
        time += array[i].data[k].count;
      }
      if (time > 0) {
        let temp;
        for (k = 0; k < array[i].data.length; k++) {
          if (array[i].data[k].count == 0)
            continue;
          temp = array[i].data[k].count * 100.0 / time;
          sql = temp.toString();
          if (sql.indexOf('.') > 0) {
            if (sql.split('.')[1].length > 1)
              array[i].data[k].ratio = temp.toFixed(1);
            else
              array[i].data[k].ratio = sql;
          }
          else {
            array[i].data[k].ratio = sql + '.0';
          }
          array[i].data[k].ratio += '%';
        }
      }
    }

    res.status(200);
    res.json({ "result": "ok", "order": array, "list": list });
  }
  catch (error) {
    console.log('QueryBaobiaoDelay error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})
// 领用明细报表 FSMS
app.post('/QueryBaobiaoLingyong', async (req, res) => {
  try {
    // 准备好查询的时间
    let date = new Date();
    let starttime = 0;
    let endtime = date.getTime();
    if (req.body.starttime != undefined)
    // 轉成時間戳
      starttime = Date.parse(req.body.starttime);
    if (req.body.endtime != undefined)
      endtime = Date.parse(req.body.endtime);
    let array = new Array();
    let i, j, k, time = 0;
    let sql = "select * from base_material";
    let material = await db_util.query(sql);
    sql = "select * from machining_union_sheet where lingqu_time != '' ORDER BY lingqu_time";
    let suc = await db_util.query(sql);
    // 对于machining_union_sheet表
    // 1.设置time、用j、k判断是否已领取
    // 2.根据工联单号获取machining_sheet表数据
    //   2.1 设置 material_type、unit、material_name
    //   2.2 设置 从machining_union_sheet、machining_sheet、2.1的变量
    //       获取返回json的大部分数据
    //       即从machining_union_sheet表、machining_sheet表双层遍历给array添加第一批数据
    for (i = 0; i < suc.length; i++) {
      time = Date.parse(suc[i].lingqu_time);
      if (isNaN(time))
        time = 0;
      if (time < starttime || time >= endtime)
        continue;
      // 看是否已全部领取
      j = await GetLingquCount(suc[i].union_order); // 已领取
      k = parseInt(suc[i].quatity); // 总数
      if (j < k) {
        console.log('领用明细报表：未全部领取，总表ID：' + suc[i].id + '，数量：' + k + '，已领取：' + j);
        continue;
      }
      date.setTime(time);
      sql = "select * from machining_sheet where quatity != '0' and union_order = '" + suc[i].union_order + "'";
      let succ2 = await db_util.query(sql);
      let material_type = "";
      let unit = "";
      let material_name = "";
      let temp = 0.0;
      for (k = 0; k < succ2.length; k++) {
        for (j = 0; j < material.length; j++) {
          if (material[j].material_no == succ2[k].material_no) {
            material_type = material[j].type;
            unit = material[j].unit;
            material_name = material[j].name;
            break;
          }
        }
        let json = {};
        json["date"] = getMonthDayTime(date, 1);
        json["unionorder"] = suc[i].union_order;
        json["name"] = succ2[k].sheet_order;
        json["machine"] = suc[i].machine_type;
        json["xuhao"] = "";
        json["type"] = succ2[k].type;
        json["workorder"] = material_name;
        json["material_no"] = succ2[k].material_no;
        json["material_type"] = material_type;
        temp = parseFloat(succ2[k].yibei_shuliang);
        if (isNaN(temp))
          temp = 0;
        json["quatity"] = temp;
        temp = parseFloat(succ2[k].tuiku_shuliang);
        if (isNaN(temp))
          temp = 0;
        json["quatity"] -= temp;
        json["unit"] = unit;
        json["charge"] = suc[i].charge_department;
        json["apply_person"] = suc[i].apply_person;
        json["cost"] = 0.0; // 材料费用
        sql = "select * from material_send where union_order = '" + suc[i].union_order + "' and sheet_order = '" + succ2[k].sheet_order + "'";
        let suc2 = await db_util.query(sql);
        temp = 0.0;
        for (j = 0; j < suc2.length; j++) {
          let quatity = parseFloat(suc2[j].quatity);
          if (isNaN(quatity))
            quatity = 0;
          let price = parseFloat(suc2[j].price); // 此价格是税后价格
          if (isNaN(price)) {
            console.log('查询料号税后价格：' + suc[i].union_order + ' - ' + suc2[j].material_no + '不存在');
            price = 0.0;
          }
          if (quatity < 0) // 退库
          {
            let id = parseInt(suc2[j]['warehouse_id']);
            if (isNaN(id) == false) {
              id -= 300000000;
              sql = "select price, manufacturer from warehouse where id = '" + id + "'";
              let succ3 = await db_util.query(sql);
              if (succ3.length > 0) {
                let m = parseFloat(succ3[0]['price']);
                if (m == price && m != 0) {
                  price = await GetPriceAfterTax(succ3[0]['price'], succ3[0]['manufacturer']); // 转成未税价
                  //console.log('material_send', suc2[j]['id'], suc2[j]['warehouse_id'], succ3[0]['price'], succ3[0]['manufacturer'], '转成未税价', price);
                }
              }
            }
          }
          json["cost"] += quatity * price;
          temp += quatity;
        }
        json["quatity"] = dotFixed(temp, 3);
        json["remark"] = "";
        json["cost"] = dotFixed(json["cost"]);
        // 1-加工件；0-标准件
        if (succ2[k]['type_flag'] == 0) {
          json['lingliao_riqi'] = succ2[k]['lingliao_riqi'];
        }
        else {
          sql = "select id, timestamp from material_send where union_order = '" + succ2[k]['union_order'] + "' and sheet_order = '" + succ2[k]['sheet_order'] + "' ORDER BY timestamp DESC";
          let succ4 = await db_util.query(sql);
          if (succ4.length > 0) {
            json['lingliao_riqi'] = succ4[0]['timestamp'].substr(0, 10);
          }
        }
        if (json['lingliao_riqi'] == '')
          json['status'] = '未結單';
        else
          json['status'] = '已結單';
        array.push(json);// 第一批数据
      }//machining_sheet遍历
    }//machining_union_sheet遍历

    // 遍历material_apply表给 array添加第二批数据
    suc = null;
    sql = "select * from material_apply where lingliao_riqi != '' ORDER BY lingliao_riqi";
    suc = await db_util.query(sql);
    for (i = 0; i < suc.length; i++) {
      time = Date.parse(suc[i].lingliao_riqi);
      if (isNaN(time))
        time = 0;
      if (time < starttime || time >= endtime)
        continue;
      for (j = 0; j < material.length; j++) {
        if (material[j].material_no == suc[i].material_no) {
          material_type = material[j].type;
          unit = material[j].unit;
          material_name = material[j].name;
          break;
        }
      }
      let json = {};
      json["date"] = suc[i].lingliao_riqi;
      json['lingliao_riqi'] = suc[i]['lingliao_riqi'];
      json['status'] = '已結單';
      if (suc[i]['union_order'] != '') {
        json["unionorder"] = suc[i]['union_order'];
        json["name"] = suc[i].applyID;
      }
      else {
        json["unionorder"] = suc[i].applyID;
        json["name"] = suc[i].applyType;
      }
      json["machine"] = "";
      json["xuhao"] = "";
      json["type"] = suc[i].applyType;
      json["workorder"] = suc[i].name;
      json["material_no"] = suc[i].material_no;
      json["material_type"] = material_type;
      //json["quatity"] = suc[i].quatity;
      temp = parseFloat(suc[i].yibei_shuliang);
      if (isNaN(temp))
        temp = 0;
      json["quatity"] = temp;
      temp = parseFloat(suc[i].tuiku_shuliang);
      if (isNaN(temp))
        temp = 0;
      json["quatity"] -= temp;
      json["unit"] = unit;
      json["charge"] = suc[i].charge_department;
      json["apply_person"] = suc[i].applicant;
      json["cost"] = 0.0; // 材料费用
      sql = "select * from material_send where union_order = '" + suc[i].applyID + "' and sheet_order = '領用單'";
      let suc2 = await db_util.query(sql);
      temp = 0.0;
      for (j = 0; j < suc2.length; j++) {
        let quatity = parseFloat(suc2[j].quatity);
        if (isNaN(quatity))
          quatity = 0;
        let price = parseFloat(suc2[j].price); // 此价格是税后价格
        if (isNaN(price)) {
          console.log('查询料号税后价格：' + suc[i].applyID + ' - ' + suc2[j].material_no + '不存在');
          price = 0.0;
        }
        if (quatity < 0) // 退库
        {
          let id = parseInt(suc2[j]['warehouse_id']);
          if (isNaN(id) == false) {
            id -= 300000000;
            sql = "select price, manufacturer from warehouse where id = '" + id + "'";
            let succ3 = await db_util.query(sql);
            if (succ3.length > 0) {
              let m = parseFloat(succ3[0]['price']);
              if (m == price && m != 0) {
                price = await GetPriceAfterTax(succ3[0]['price'], succ3[0]['manufacturer']); // 转成未税价
                //console.log('material_send', suc2[j]['id'], suc2[j]['warehouse_id'], succ3[0]['price'], succ3[0]['manufacturer'], '转成未税价', price);
              }
            }
          }
        }
        json["cost"] += quatity * price;
        temp += quatity;
      }
      json["quatity"] = dotFixed(temp);
      json["remark"] = suc[i]['remark'];
      json["cost"] = dotFixed(json["cost"]);
      array.push(json);
    }//material_apply遍历

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryBaobiaoLingyong error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})
// 呆滞料报表：三个月未领用的物料统计 FSMS
app.post('/QueryBaobiaoDaizhiliao', async (req, res) => {
  console.log("开始统计呆滞料数据");
  try {
    let i, j, k, m, temp;
    let date = new Date();
    let currentTime = date.getTime();
    let currentmonth = date.getMonth();
    if (date.getDate() > 20)
      currentmonth++;
    date.setDate(21);
    setTime(date, 0, 0, 0, 0);
    let starttime = "";
    let endtime = "";
    let array = new Array();
    let list = new Array();
    let month_name = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    let sql = "select * from warehouse ORDER BY timestamp ASC";
    let suc = await db_util.query(sql);
    sql = "select * from base_material";
    let succ4 = await db_util.query(sql);
    let dt = new Date();
    for (k = 0; k < 12; k++) {
      if (k >= currentmonth) {
        date.setTime(currentTime);
        setTime(date, 23, 59, 59, 999);
        starttime = getMonthDayTime(date, 1, 1);
        j = date.getTime() - 90 * 24 * 3600 * 1000;
      }
      else {
        date.setMonth(k);
        starttime = getMonthDayTime(date, 1, 1);
        j = date.getTime() - 90 * 24 * 3600 * 1000;
      }
      dt.setTime(j);
      endtime = getMonthDayTime(dt, 1, 1);
      let json = {};
      json["month_name"] = month_name[k];
      json["kucunjine"] = 0;
      json["daizhi"] = 0;
      json["kucun_cailiao"] = 0;
      json["kucun_peijian"] = 0;
      json["kucun_daoju"] = 0;
      json["kucun_haocai"] = 0;
      json["kucun_shebeibeijian"] = 0;
      json["kucun_qita"] = 0;
      json["daizhi_cailiao"] = 0;
      json["daizhi_peijian"] = 0;
      json["daizhi_daoju"] = 0;
      json["daizhi_haocai"] = 0;
      json["daizhi_shebeibeijian"] = 0;
      json["daizhi_qita"] = 0;
      i = 0;
      if (k > currentmonth)
        i = suc.length;
      for (; i < suc.length; i++) {
        if (k < currentmonth && suc[i]["timestamp"] >= starttime)
          break;
        for (j = 0; j < succ4.length; j++) {
          if (succ4[j]["material_no"] == suc[i]["material_no"])
            break;
        }
        temp = (parseFloat(suc[i].quatity) - parseFloat(suc[i].usedQuatity)) * parseFloat(suc[i].price);
        temp = await GetPriceAfterTax(temp, suc[i]["manufacturer"], 2);
        json["kucunjine"] += temp;
        if (succ4.length > j) {
          if (succ4[j]["type"].indexOf("設備備件") >= 0)
            json["kucun_shebeibeijian"] += temp;
          else if (succ4[j]["type"].indexOf("材料") >= 0)
            json["kucun_cailiao"] += temp;
          else if (succ4[j]["type"].indexOf("配件") >= 0)
            json["kucun_peijian"] += temp;
          else if (succ4[j]["type"].indexOf("刀具") >= 0)
            json["kucun_daoju"] += temp;
          else if (succ4[j]["type"].indexOf("耗材") >= 0)
            json["kucun_haocai"] += temp;
          else
            json["kucun_qita"] += temp;
        }
        if (suc[i].timestamp > endtime) // 最近3个月内有采购入库，不参与呆滞料的统计
          continue;
        sql = "select * from material_send where quatity > 0 and timestamp > '" + endtime + "' and material_no = '" + suc[i].material_no + "' ORDER BY id DESC LIMIT 1";
        let succ2 = await db_util.query(sql);
        if (succ2.length > 0) // 最近3个月内有发料使用则不算呆滞料
          continue;
        json["daizhi"] += temp;
        if (succ4.length > j) {
          if (succ4[j]["type"].indexOf("設備備件") >= 0)
            json["daizhi_shebeibeijian"] += temp;
          else if (succ4[j]["type"].indexOf("材料") >= 0)
            json["daizhi_cailiao"] += temp;
          else if (succ4[j]["type"].indexOf("配件") >= 0)
            json["daizhi_peijian"] += temp;
          else if (succ4[j]["type"].indexOf("刀具") >= 0)
            json["daizhi_daoju"] += temp;
          else if (succ4[j]["type"].indexOf("耗材") >= 0)
            json["daizhi_haocai"] += temp;
          else
            json["daizhi_qita"] += temp;
        }
        if (k < currentmonth)
          continue;
        if (succ4.length == j) // 没有找到料号基本信息
          continue;

        for (m = 0; m < list.length; m++) {
          if (list[m]["material_no"] == suc[i]["material_no"])
            break;
        }
        if (m == list.length) {
          let json2 = {};
          json2["PR_NO"] = suc[i].PR_NO;
          json2["PO_NO"] = suc[i].PO_NO;
          json2["SN"] = suc[i].SN;
          json2["material_no"] = suc[i].material_no;
          json2["quatity"] = 0;
          json2["price"] = 0;
          json2["manufacturer"] = suc[i].manufacturer;
          json2["currency"] = suc[i].currency;
          json2["check_no"] = suc[i].check_no;
          json2["reason"] = suc[i].purchasing_reason;
          json2["time"] = suc[i].timestamp;

          json2["name"] = succ4[j].name;
          json2["type"] = succ4[j].type;
          json2["price_total"] = 0;
          json2["normal_month"] = suc[i].timestamp.substr(0, 7);

          list.push(json2);
        }
        list[m]["price"] = suc[i].price;
        list[m]["price_total"] += temp;
        temp = parseFloat(suc[i].quatity);
        if (isNaN(temp))
          temp = 0;
        list[m]["quatity"] += temp;
        temp = parseFloat(suc[i].usedQuatity);
        if (isNaN(temp))
          temp = 0;
        list[m]["quatity"] -= temp;
      }
      json["kucunjine"] = dotFixed(json["kucunjine"]);
      json["daizhi"] = dotFixed(json["daizhi"]);
      json["kucun_cailiao"] = dotFixed(json["kucun_cailiao"]);
      json["kucun_peijian"] = dotFixed(json["kucun_peijian"]);
      json["kucun_daoju"] = dotFixed(json["kucun_daoju"]);
      json["kucun_haocai"] = dotFixed(json["kucun_haocai"]);
      json["kucun_shebeibeijian"] = dotFixed(json["kucun_shebeibeijian"]);
      json["kucun_qita"] = dotFixed(json["kucun_qita"]);
      json["daizhi_cailiao"] = dotFixed(json["daizhi_cailiao"]);
      json["daizhi_peijian"] = dotFixed(json["daizhi_peijian"]);
      json["daizhi_daoju"] = dotFixed(json["daizhi_daoju"]);
      json["daizhi_haocai"] = dotFixed(json["daizhi_haocai"]);
      json["daizhi_shebeibeijian"] = dotFixed(json["daizhi_shebeibeijian"]);
      json["daizhi_qita"] = dotFixed(json["daizhi_qita"]);
      array.push(json);
    }
    for (i = 0; i < list.length; i++) {
      list[i]["price_total"] = dotFixed(list[i]["price_total"]);
    }
    i = (Date.now() - currentTime) / 1000;
    console.log("呆滞料报表花费时间：" + i + '，明细记录条数：' + list.length);

    res.status(200);
    res.json({ "result": "ok", "order": array, "list": list });
  }
  catch (error) {
    console.log('QueryBaobiaoDaizhiliao error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

function getDaysOfMonth(month, year) // month：自然月份，从1开始
{
  let days = 31;
  if (month == 2) {
    if (year != undefined) {
      if (year % 4)
        days = 28;
      else
        days = 29;
    }
    else {
      days = 28;
    }
  }
  else if (month == 4 || month == 6 || month == 9 || month == 11) {
    days = 30;
  }
  return days;
}

function getOTDWeek(date) {
  let json = {};
  let dt = new Date(date);
  let day = date.getDate();
  let month = date.getMonth();
  let year = date.getFullYear();
  if (day > 20) {
    json["month_range"] = (month + 1) + "/21~";
    json["month_range_full"] = year + "/" + (month + 1) + "/21~";
    if (month == 11) {
      json["month_range"] += "1/20";
      json["month_range_full"] += ((year + 1) + "/1/20");
    }
    else {
      json["month_range"] += ((month + 2) + "/20");
      json["month_range_full"] += (year + "/" + (month + 2) + "/20");
    }
  }
  else {
    if (month == 0) {
      json["month_range"] = "12/21~";
      json["month_range_full"] = (year - 1) + "/12/21~";
    }
    else {
      json["month_range"] = month + "/21~";
      json["month_range_full"] = year + "/" + month + "/21~";
    }
    json["month_range"] += ((month + 1) + "/20");
    json["month_range_full"] += (year + "/" + (month + 1) + "/20");
  }
  json["weekdays"] = 7;
  if (day > 20) // 到下个月
  {
    dt.setDate(20); // 防止01/29直接加一个月就变成了03/01
    dt.setMonth(month + 1);
    json["month"] = getMonthDayTime(dt);
    if (day > 27) {
      dt.setTime(date.getTime());
      dt.setDate(28);
      json["from"] = getMonthDayTime(dt, 1);
      dt.setTime(dt.getTime() + 6 * 24 * 3600 * 1000);
      json["to"] = getMonthDayTime(dt, 1);
      json["week"] = 2;
    }
    else {
      json["from"] = getMonthDayTime(date) + '-21';
      json["to"] = getMonthDayTime(date) + '-27';
      json["week"] = 1;
    }
  }
  else {
    json["month"] = getMonthDayTime(date);
    dt.setMonth(month - 1);
    dt.setDate(28);
    json["from"] = getMonthDayTime(dt, 1);
    let currTime = dt.getTime() + 6 * 24 * 3600 * 1000;
    dt.setTime(currTime);
    let day2 = dt.getDate();
    if (day <= day2) {
      json["to"] = getMonthDayTime(dt, 1);
      json["week"] = 2;
    }
    else if (day <= (day2 + 7)) {
      currTime += 24 * 3600 * 1000;
      dt.setTime(currTime);
      json["from"] = getMonthDayTime(dt, 1);
      currTime += 6 * 24 * 3600 * 1000;
      dt.setTime(currTime);
      json["to"] = getMonthDayTime(dt, 1);
      json["week"] = 3;
    }
    else {
      currTime += 8 * 24 * 3600 * 1000;
      dt.setTime(currTime);
      json["from"] = getMonthDayTime(dt, 1);
      let temp = dt.getDate();
      dt.setDate(20);
      json["to"] = getMonthDayTime(dt, 1);
      json["week"] = 4;
      json["weekdays"] = 21 - temp;
    }
  }
  dt.setTime(Date.parse(json["from"]));
  json["range"] = (dt.getMonth() + 1) + '/' + dt.getDate() + '~';
  dt.setTime(Date.parse(json["to"]));
  json["range"] += ((dt.getMonth() + 1) + '/' + dt.getDate());
  if (day > 20) // 到下个月
  {
    month++;
    if (month > 11)
      month = 0;
  }
  let arr = ['JAN.', 'FEB.', 'MAR.', 'APR.', 'MAY.', 'JUN.', 'JUL.', 'AUG.', 'SEP.', 'OCT.', 'NOV.', 'DEC.'];
  json["month_name"] = arr[month];
  if (month == 0)
    month = 12;
  json["days"] = getDaysOfMonth(month, year);
  return json;
}
//FSMS
app.post('/QueryBaobiaoOTD', async (req, res) => {
  try {
    let date = new Date();
    let currentmonth = getOTDWeek(date).month;
    let i, j, k, begin = -1;
    let array = new Array();
    i = date.getFullYear() - 1;
    date.setFullYear(i, 11, 21); // 从上一年的12月21日开始
    let starttime = date.getTime();
    if (req.body.starttime != undefined) {
      starttime = Date.parse(req.body.starttime);
      if (isNaN(starttime))
        starttime = date.getTime();
    }
    let sql = "select * from machining_union_sheet where lingqu_time != '' ORDER BY delivery_date ASC";
    let suc = await db_util.query(sql);
    for (i = 0; i < suc.length; i++) {
      k = Date.parse(suc[i].lingqu_time);
      if (k >= starttime) {
        begin = i;
        break;
      }
    }
    if (begin < 0) {
      res.status(200);
      res.json({ "result": "ok", "order": array });
      return;
    }
    let currentTime = starttime;//Date.parse(suc[begin].delivery_date);
    date.setTime(currentTime);
    let first = getOTDWeek(date);
    let json = {};
    json["month"] = first.month;
    json["month_name"] = first.month_name;
    json["ok"] = 0;
    json["delay"] = 0;
    json["data"] = new Array();
    let json2 = {};
    json2["from"] = first.from;
    json2["to"] = first.to;
    json2["range"] = first.range;
    json2["ok"] = 0;
    json2["delay"] = 0;
    json["data"].push(json2);
    array.push(json);
    //if( suc.length > 1 )
    {
      //date.setTime(Date.parse(suc[suc.length-1].delivery_date));
      i = date.getMonth();
      if (i == 0) {
        date.setMonth(11);
        date.setDate(20);
      }
      else {
        date.setFullYear(date.getFullYear() + 1);
        date.setMonth(i - 1);
        date.setDate(20);
      }
      let last = getOTDWeek(date);
      while (suc.length > 1) {
        currentTime += 7 * 24 * 3600 * 1000;
        date.setTime(currentTime);
        first = getOTDWeek(date);
        if (first.to > last.to)
          break;
        for (i = 0; i < array.length; i++) {
          if (array[i]["month"] == first.month) {
            for (k = 0; k < array[i]["data"].length; k++) {
              if (array[i]["data"][k].range == first.range)
                break;
            }
            if (k == array[i]["data"].length) {
              let json2 = {};
              json2["from"] = first.from;
              json2["to"] = first.to;
              json2["range"] = first.range;
              json2["ok"] = 0;
              json2["delay"] = 0;
              array[i]["data"].push(json2);
            }
            break;
          }
        }
        if (i == array.length) {
          let json = {};
          json["month"] = first.month;
          json["month_name"] = first.month_name;
          json["ok"] = 0;
          json["delay"] = 0;
          json["data"] = new Array();
          let json2 = {};
          json2["from"] = first.from;
          json2["to"] = first.to;
          json2["range"] = first.range;
          json2["ok"] = 0;
          json2["delay"] = 0;
          json["data"].push(json2);
          array.push(json);
        }
      }
    }
    for (i = 0; i < suc.length; i++) {
      date.setTime(Date.parse(suc[i].delivery_date));
      sql = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and rawdata != 0";
      let succ2 = await db_util.query(sql);
      let jiagong_end_date = "";
      let ercijg_end_date = "";
      for (k = 0; k < succ2.length; k++) {
        if (succ2[k].end_date > jiagong_end_date)
          jiagong_end_date = succ2[k].end_date;
        if (succ2[k].machine_end_date_2 > ercijg_end_date)
          ercijg_end_date = succ2[k].machine_end_date_2;
      }
      first = getOTDWeek(date);
      for (j = 0; j < array.length; j++) {
        if (array[j]["month"] == first.month) {
          for (k = 0; k < array[j]["data"].length; k++) {
            if (array[j]["data"][k].range == first.range) {
              let time = Date.parse(suc[i].design_end_date);
              if (suc[i].sheji_endtime == '')
                currentTime = Date.now();
              else
                currentTime = Date.parse(suc[i].sheji_endtime);
              if (currentTime > time) {
                array[j]["data"][k]["delay"] += 1;
                //console.log('设计Delay：' + suc[i].union_order + '，期限：' + suc[i].design_end_date + '，结束：' + suc[i].sheji_endtime);
              }
              else {
                array[j]["data"][k]["ok"] += 1;
              }

              time = Date.parse(jiagong_end_date);
              if (suc[i].jiagong_endtime == '')
                currentTime = Date.now();
              else
                currentTime = Date.parse(suc[i].jiagong_endtime);
              if (currentTime > time) {
                array[j]["data"][k]["delay"] += 1;
                //console.log('加工Delay：' + suc[i].union_order + '，期限：' + jiagong_end_date + '，结束：' + suc[i].jiagong_endtime);
              }
              else {
                array[j]["data"][k]["ok"] += 1;
              }

              time = Date.parse(ercijg_end_date);
              if (suc[i].ercijg_endtime == '')
                currentTime = Date.now();
              else
                currentTime = Date.parse(suc[i].ercijg_endtime);
              if (currentTime > time) {
                array[j]["data"][k]["delay"] += 1;
                //console.log('二次Delay：' + suc[i].union_order + '，期限：' + ercijg_end_date + '，结束：' + suc[i].ercijg_endtime);
              }
              else {
                array[j]["data"][k]["ok"] += 1;
              }

              time = Date.parse(suc[i].assemble_end_date);
              if (suc[i].zuzhuang_endtime == '')
                currentTime = Date.now();
              else
                currentTime = Date.parse(suc[i].zuzhuang_endtime);
              if (currentTime > time) {
                array[j]["data"][k]["delay"] += 1;
                //console.log('组装Delay：' + suc[i].union_order + '，期限：' + suc[i].assemble_end_date + '，结束：' + suc[i].zuzhuang_endtime);
              }
              else {
                array[j]["data"][k]["ok"] += 1;
              }

              time = Date.parse(suc[i].delivery_date);
              if (suc[i].lingqu_time == '')
                currentTime = Date.now();
              else
                currentTime = Date.parse(suc[i].lingqu_time);
              if (currentTime > time) {
                array[j]["data"][k]["delay"] += 1;
                //console.log('入库Delay：' + suc[i].union_order + '，期限：' + suc[i].delivery_date + '，结束：' + suc[i].ruku_time);
              }
              else {
                array[j]["data"][k]["ok"] += 1;
              }
              break;
            }
          }
          break;
        }
      }
    }

    for (i = 0; i < array.length; i++) {
      for (k = 0; k < array[i]["data"].length; k++) {
        array[i]["ok"] += array[i]["data"][k]["ok"];
        array[i]["delay"] += array[i]["data"][k]["delay"];
      }
      if (array[i]["month"] != currentmonth) {
        array[i]["data"].length = 0;
      }
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryBaobiaoOTD error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

function AddItemOrderByDate(array, json) {
  let i = 0;
  for (; i < array.length; i++) {
    if (json["date"] < array[i]["date"]) {
      array.splice(i, 0, json);
      break;
    }
    else if (json["date"] == array[i]["date"]) {
      if (json["unionorder"] < array[i]["unionorder"]) {
        array.splice(i, 0, json);
        break;
      }
    }
  }
  if (i >= array.length)
    array.push(json);
}

//FSMS
app.post('/QueryBaobiaoBenefit', async (req, res) => {
  try {
    let date = new Date();
    let currentOTDWeek = getOTDWeek(date);
    let currentmonth = currentOTDWeek.month;
    let i, j, k, index, begin = -1;
    let array = new Array();
    let mingxi = new Array();
    let mingxi2 = new Array();
    let arr3 = new Array();
    i = date.getFullYear() - 1;
    date.setFullYear(i, 11, 21); // 从上一年的12月21日开始
    index = date.getTime();
    if (req.body.starttime != undefined) {
      index = Date.parse(req.body.starttime);
      if (isNaN(index))
        index = date.getTime();
    }
    let sql = "select * from machining_union_sheet where lingqu_time != '' and price != '' and status != 2 ORDER BY lingqu_time ASC";
    let suc = await db_util.query(sql);
    for (i = 0; i < suc.length; i++) {
      k = Date.parse(suc[i].lingqu_time);
      if (k >= index) {
        begin = i;
        break;
      }
    }
    if (begin < 0) {
      res.status(200);
      res.json({ "result": "ok", "order": array });
      return;
    }
    let currentTime = index;//Date.parse(suc[begin].ruku_time);
    date.setTime(currentTime);
    let first = getOTDWeek(date);
    let json = {};
    json["month"] = first.month;
    json["month_name"] = first.month_name;
    json["month_range"] = first.month_range;
    json["yunying"] = 0;
    json["wuliao"] = 0;
    json["zhichu"] = 0;
    json["yingyee"] = 0;
    json["chunlirun"] = 0;
    json["cailiaofei"] = 0;
    json["daojuhaocai"] = 0;
    json["data"] = new Array();
    let json2 = {};
    json2["from"] = first.from;
    json2["to"] = first.to;
    json2["range"] = first.range;
    json2["week"] = first.week;
    json2["weekdays"] = first.weekdays;
    json2["days"] = first.days;
    json2["yunying"] = 0;
    json2["wuliao"] = 0;
    json2["zhichu"] = 0;
    json2["yingyee"] = 0;
    json2["chunlirun"] = 0;
    json2["cailiaofei"] = 0;
    json2["daojuhaocai"] = 0;
    json["data"].push(json2);
    array.push(json);
    let starttime = first.from;
    let endtime = first.to;
    //if( suc.length > 0 )
    {
      date.setTime(Date.now());
      let last = getOTDWeek(date);
      endtime = last.to;
      currentmonth = last.month;
      while (currentTime > 0) {
        currentTime += 7 * 24 * 3600 * 1000;
        date.setTime(currentTime);
        first = getOTDWeek(date);
        if (first.to > last.to)
          break;
        for (i = 0; i < array.length; i++) {
          if (array[i]["month"] == first.month) {
            for (k = 0; k < array[i]["data"].length; k++) {
              if (array[i]["data"][k].range == first.range)
                break;
            }
            if (k == array[i]["data"].length) {
              let json2 = {};
              json2["from"] = first.from;
              json2["to"] = first.to;
              json2["range"] = first.range;
              json2["week"] = first.week;
              json2["weekdays"] = first.weekdays;
              json2["days"] = first.days;
              json2["yunying"] = 0;
              json2["wuliao"] = 0;
              json2["zhichu"] = 0;
              json2["yingyee"] = 0;
              json2["chunlirun"] = 0;
              json2["cailiaofei"] = 0;
              json2["daojuhaocai"] = 0;
              array[i]["data"].push(json2);
            }
            break;
          }
        }
        if (i == array.length) {
          let json = {};
          json["month"] = first.month;
          json["month_name"] = first.month_name;
          json["month_range"] = first.month_range;
          json["yunying"] = 0;
          json["wuliao"] = 0;
          json["zhichu"] = 0;
          json["yingyee"] = 0;
          json["chunlirun"] = 0;
          json["cailiaofei"] = 0;
          json["daojuhaocai"] = 0;
          json["data"] = new Array();
          let json2 = {};
          json2["from"] = first.from;
          json2["to"] = first.to;
          json2["range"] = first.range;
          json2["week"] = first.week;
          json2["weekdays"] = first.weekdays;
          json2["days"] = first.days;
          json2["yunying"] = 0;
          json2["wuliao"] = 0;
          json2["zhichu"] = 0;
          json2["yingyee"] = 0;
          json2["chunlirun"] = 0;
          json2["cailiaofei"] = 0;
          json2["daojuhaocai"] = 0;
          json["data"].push(json2);
          array.push(json);
        }
      }
    }
    for (i = begin; i < suc.length; i++) {
      date.setTime(Date.parse(suc[i].lingqu_time));
      first = getOTDWeek(date);
      let cailiaofei = 0;
      let quatity = parseInt(suc[i].quatity);
      let lingqu_count = 0;
      sql = "select * from delivery_sheet where union_order = '" + suc[i].union_order + "'";
      let suc3 = await db_util.query(sql);
      for (k = 0; k < suc3.length; k++) {
        j = parseInt(suc3[k].quatity);
        if (isNaN(j))
          j = 0;
        lingqu_count += j;
      }
      if (lingqu_count < quatity)
        first = currentOTDWeek;

      for (j = 0; j < array.length; j++) {
        if (array[j]["month"] == first.month) {
          for (k = 0; k < array[j]["data"].length; k++) {
            if (array[j]["data"][k].range == first.range) {
              if (lingqu_count == quatity) {
                sql = "select * from material_send where union_order = '" + suc[i].union_order + "'";
                let succ2 = await db_util.query(sql);
                for (index = 0; index < succ2.length; index++) {
                  let feiyong = parseFloat(succ2[index].quatity) * parseFloat(succ2[index].price);
                  array[j]["data"][k]["cailiaofei"] += feiyong;
                  cailiaofei += feiyong;
                }
                succ2 = null;
                sql = "select * from material_send where other_order = '" + suc[i].union_order + "'";
                succ2 = await db_util.query(sql);
                if (succ2.length > 0) {
                  arr3.push(suc[i].union_order);
                }
                for (index = 0; index < succ2.length; index++) {
                  let feiyong = parseFloat(succ2[index].quatity) * parseFloat(succ2[index].price);
                  array[j]["data"][k]["cailiaofei"] += feiyong;
                  cailiaofei += feiyong;
                }
                array[j]["data"][k]["yingyee"] += (quatity * parseFloat(suc[i].price));
              }
              else {
                cailiaofei = quatity * parseFloat(suc[i].price) * 0.3;
                array[j]["data"][k]["cailiaofei"] += cailiaofei;
                console.log('未结单：' + suc[i].id + ', ' + suc[i].union_order + ', ' + suc[i].delivery_date + ', cost=' + cailiaofei);
              }
              break;
            }
          }
          break;
        }
      }
      cailiaofei = dotFixed(cailiaofei);

      let json = {};
      if (lingqu_count == quatity)
        json["date"] = suc[i].lingqu_time.substr(0, 10);
      else
        json["date"] = suc[i].delivery_date;
      json["unionorder"] = suc[i].union_order;
      json["name"] = suc[i].name;
      json["quatity"] = suc[i].quatity;
      json["apply_persopn"] = suc[i].apply_person;
      json["factory"] = suc[i].factory;
      json["charge_department"] = suc[i].charge_department;
      if (lingqu_count == quatity) {
        json["TTL_hour"] = suc[i].total_time;
        json["cost"] = cailiaofei;
      }
      json["price"] = suc[i].price;
      json["total_price"] = dotFixed(quatity * parseFloat(suc[i].price));
      if (lingqu_count == quatity)
        mingxi.push(json);
      else
        AddItemOrderByDate(mingxi2, json);
    }

    starttime += " 00:00:00";
    endtime += " 23:59:59";
    sql = "select * from material_send where sheet_order = '領用單' and timestamp >= '" + starttime + "' and timestamp <= '" + endtime + "'";
    let succ3 = await db_util.query(sql);
    for (i = 0; i < succ3.length; i++) {
      if (arr3.length > 0 && succ3[i]['other_order'] != '') {
        for (j = 0; j < arr3.length; j++) {
          if (succ3[i]['other_order'] == arr3[j]) {
            break;
          }
        }
        if (j < arr3.length) {
          continue; // 前面已经算过了
        }
      }
      let quatity = parseFloat(succ3[i].quatity);
      let price = parseFloat(succ3[i].price);
      date.setTime(Date.parse(succ3[i].timestamp));
      first = getOTDWeek(date);
      for (j = 0; j < array.length; j++) {
        if (array[j]["month"] == first.month) {
          for (k = 0; k < array[j]["data"].length; k++) {
            if (array[j]["data"][k].range == first.range) {
              array[j]["data"][k]["daojuhaocai"] += quatity * price;
              break;
            }
          }
          break;
        }
      }

      let json = {};
      json["date"] = succ3[i].timestamp.substr(0, 10);
      json["unionorder"] = succ3[i].union_order;
      json["name"] = succ3[i].sheet_order;
      json["quatity"] = dotFixed(succ3[i].quatity);
      sql = "select * from material_apply where applyID = '" + json["unionorder"] + "'";
      let suc4 = await db_util.query(sql);
      if (suc4.length > 0) {
        json["apply_persopn"] = suc4[0].applicant;
        json["factory"] = "";
        json["charge_department"] = suc4[0].charge_department;
      }
      else {
        json["apply_persopn"] = "";
        json["factory"] = "";
        json["charge_department"] = "";
      }
      json["TTL_hour"] = "";
      json["cost"] = dotFixed(quatity * price);
      json["price"] = "";
      json["total_price"] = "";
      mingxi.push(json);
    }

    let current_month = 0;
    let current_week = 0;
    for (k = 0; k < array.length; k++) {
      if (array[k]["month"] == currentmonth) {
        // 增加下个月的第1、2、3周
        current_month = k;
        current_week = array[k]["data"].length - 1;
        i = Date.parse(array[k]["data"][current_week]["to"]);
        i += 24 * 3600 * 1000;
        j = i + 6 * 24 * 3600 * 1000;
        {
          let json2 = {};
          date.setTime(i);
          json2["from"] = getMonthDayTime(date, 1);
          json2["range"] = (date.getMonth() + 1) + "/" + date.getDate() + "~";
          date.setTime(j);
          json2["to"] = getMonthDayTime(date, 1);
          json2["range"] += ((date.getMonth() + 1) + "/" + date.getDate());
          json2["week"] = 5;
          json2["weekdays"] = 7;
          json2["days"] = 28;
          json2["yunying"] = 0;
          json2["wuliao"] = 0;
          json2["zhichu"] = 0;
          json2["yingyee"] = 0;
          json2["chunlirun"] = 0;
          json2["cailiaofei"] = 0;
          json2["daojuhaocai"] = 0;
          array[k]["data"].push(json2);
        }
        i += 7 * 24 * 3600 * 1000;
        j += 7 * 24 * 3600 * 1000;
        {
          let json2 = {};
          date.setTime(i);
          json2["from"] = getMonthDayTime(date, 1);
          json2["range"] = (date.getMonth() + 1) + "/" + date.getDate() + "~";
          date.setTime(j);
          json2["to"] = getMonthDayTime(date, 1);
          json2["range"] += ((date.getMonth() + 1) + "/" + date.getDate());
          json2["week"] = 6;
          json2["weekdays"] = 7;
          json2["days"] = 28;
          json2["yunying"] = 0;
          json2["wuliao"] = 0;
          json2["zhichu"] = 0;
          json2["yingyee"] = 0;
          json2["chunlirun"] = 0;
          json2["cailiaofei"] = 0;
          json2["daojuhaocai"] = 0;
          array[k]["data"].push(json2);
        }
        i += 7 * 24 * 3600 * 1000;
        j += 7 * 24 * 3600 * 1000;
        {
          let json2 = {};
          date.setTime(i);
          json2["from"] = getMonthDayTime(date, 1);
          json2["range"] = (date.getMonth() + 1) + "/" + date.getDate() + "~";
          date.setTime(j);
          json2["to"] = getMonthDayTime(date, 1);
          json2["range"] += ((date.getMonth() + 1) + "/" + date.getDate());
          json2["week"] = 7;
          json2["weekdays"] = 7;
          json2["days"] = 28;
          json2["yunying"] = 0;
          json2["wuliao"] = 0;
          json2["zhichu"] = 0;
          json2["yingyee"] = 0;
          json2["chunlirun"] = 0;
          json2["cailiaofei"] = 0;
          json2["daojuhaocai"] = 0;
          array[k]["data"].push(json2);
        }
        break;
      }
    }
    suc = null;
    sql = "select * from machining_union_sheet where lingqu_time = '' and price != '' and status != 2 ORDER BY delivery_date ASC";
    suc = await db_util.query(sql);
    for (i = 0; i < suc.length; i++) {
      begin = Date.parse(suc[i].delivery_date);
      if (begin < starttime)
        continue;
      for (j = current_week; j < array[current_month]["data"].length; j++) {
        index = Date.parse(array[current_month]["data"][j]["to"]);
        if (begin <= index) {
          array[current_month]["data"][j]["cailiaofei"] += (parseFloat(suc[i].price) * parseInt(suc[i].quatity) * 0.3);
          break;
        }
      }
      if (j == array[k]["data"].length) {
        j--;
        console.log('利润报表未结单第三周，总表ID：' + suc[i].id + '，总价：' + suc[i].price + ' * ' + suc[i].quatity);
        array[current_month]["data"][j]["cailiaofei"] += (parseFloat(suc[i].price) * parseInt(suc[i].quatity) * 0.3);
      }
      let json = {};
      json["date"] = suc[i].delivery_date;
      json["unionorder"] = suc[i].union_order;
      json["name"] = suc[i].name;
      json["quatity"] = suc[i].quatity;
      json["apply_persopn"] = suc[i].apply_person;
      json["factory"] = suc[i].factory;
      json["charge_department"] = suc[i].charge_department;
      json["price"] = suc[i].price;
      json["total_price"] = dotFixed(parseInt(suc[i].quatity) * parseFloat(suc[i].price));
      mingxi2.push(json);
    }

    let year = "";
    let month = "";
    for (i = 0; i < array.length; i++) {
      year = array[i]["month"].substr(0, 4);
      month = array[i]["month"].substr(5);
      year += "/";
      year += month;
      sql = "select * from cncother where name = 'yunying' and reserved like '" + year + "'";
      let succ4 = await db_util.query(sql);
      let rent = 0;
      let dlperson = 0, dlhumancost = 0, idlperson = 0, idlhumancost = 0;
      let dlhours = 0, idlhours = 0, dlovertime = 0, idlovertime = 0;
      for (j = 0; j < succ4.length; j++) {
        if (succ4[j].value == '')
          succ4[j].value = '0';
        if (succ4[j].remark == 'dlperson')
          dlperson = parseFloat(succ4[j].value);
        else if (succ4[j].remark == 'idlperson')
          idlperson = parseFloat(succ4[j].value);
        else if (succ4[j].remark == 'dlhumancost')
          dlhumancost = parseFloat(succ4[j].value);
        else if (succ4[j].remark == 'idlhumancost')
          idlhumancost = parseFloat(succ4[j].value);
        else if (succ4[j].remark == 'depreciation' || succ4[j].remark == 'rent' || succ4[j].remark == 'sdcharge')
          rent += parseFloat(succ4[j].value);
      }
      rent += (dlperson * dlhumancost + idlperson * idlhumancost);
      for (k = 0; k < array[i]["data"].length; k++) {
        array[i]["data"][k]["yunying"] += rent * array[i]["data"][k]["weekdays"] / array[i]["data"][k]["days"];
        dlhours = 0;
        dlovertime = 0;
        idlhours = 0;
        idlovertime = 0;
        for (j = 0; j < succ4.length; j++) {
          if (succ4[j].remark == 'dlovertime')
            dlovertime = parseFloat(succ4[j].value);
          else if (succ4[j].remark == 'idlovertime')
            idlovertime = parseFloat(succ4[j].value);
          if (succ4[j].other == array[i]["data"][k]["week"]) {
            if (succ4[j].remark == 'other')
              array[i]["data"][k]["yunying"] += parseFloat(succ4[j].value);
            else if (succ4[j].remark == 'dlhours')
              dlhours = parseFloat(succ4[j].value);
            else if (succ4[j].remark == 'idlhours')
              idlhours = parseFloat(succ4[j].value);
          }
        }
        array[i]["data"][k]["yunying"] += (dlhours * dlovertime + idlhours * idlovertime);

        array[i]["yunying"] += array[i]["data"][k]["yunying"];
        array[i]["yingyee"] += array[i]["data"][k]["yingyee"];
        array[i]["cailiaofei"] += array[i]["data"][k]["cailiaofei"];
        array[i]["daojuhaocai"] += array[i]["data"][k]["daojuhaocai"];

        if (array[i]["month"] == currentmonth) {
          array[i]["data"][k]["wuliao"] = array[i]["data"][k]["cailiaofei"] + array[i]["data"][k]["daojuhaocai"];
          array[i]["data"][k]["zhichu"] = array[i]["data"][k]["yunying"] + array[i]["data"][k]["wuliao"];
          array[i]["data"][k]["chunlirun"] = array[i]["data"][k]["yingyee"] - array[i]["data"][k]["zhichu"];

          array[i]["data"][k]["wuliao"] = dotFixed(array[i]["data"][k]["wuliao"]);
          array[i]["data"][k]["zhichu"] = dotFixed(array[i]["data"][k]["zhichu"]);
          array[i]["data"][k]["chunlirun"] = dotFixed(array[i]["data"][k]["chunlirun"]);
        }
      }
      array[i]["wuliao"] = array[i]["cailiaofei"] + array[i]["daojuhaocai"];
      array[i]["zhichu"] = array[i]["yunying"] + array[i]["wuliao"];
      array[i]["chunlirun"] = array[i]["yingyee"] - array[i]["zhichu"];

      array[i]["yunying"] = dotFixed(array[i]["yunying"]);
      array[i]["wuliao"] = dotFixed(array[i]["wuliao"]);
      array[i]["zhichu"] = dotFixed(array[i]["zhichu"]);
      array[i]["chunlirun"] = dotFixed(array[i]["chunlirun"]);
      array[i]["cailiaofei"] = dotFixed(array[i]["cailiaofei"]);
      array[i]["daojuhaocai"] = dotFixed(array[i]["daojuhaocai"]);

      if (array[i]["month"] != currentmonth) {
        array[i]["data"].length = 0;
      }
      else {
        for (k = 0; k < array[i]["data"].length; k++) {
          array[i]["data"][k]["yunying"] = dotFixed(array[i]["data"][k]["yunying"]);
          array[i]["data"][k]["yingyee"] = dotFixed(array[i]["data"][k]["yingyee"]);
          array[i]["data"][k]["cailiaofei"] = dotFixed(array[i]["data"][k]["cailiaofei"]);
          array[i]["data"][k]["daojuhaocai"] = dotFixed(array[i]["data"][k]["daojuhaocai"]);
        }
      }
    }

    let mingxi3 = new Array();
    for (i = 0; i < mingxi.length; i++) {
      mingxi3.push(mingxi[i]);
    }
    mingxi2.forEach(element => {
      let json = {};
      json["date"] = element['date'];
      json["unionorder"] = element['unionorder'];
      json["name"] = element['name'];
      json["quatity"] = element['quatity'];
      json["apply_persopn"] = element['apply_persopn'];
      json["factory"] = element['factory'];
      json["charge_department"] = element['charge_department'];
      json["TTL_hour"] = "";
      json["cost"] = "";
      json["price"] = element['price'];
      json["total_price"] = element['total_price'];
      mingxi3.push(json);
    });
    mingxi3.sort(keysort('date', false));

    res.status(200);
    res.json({ "result": "ok", "order": array, "mingxi": mingxi, "mingxi2": mingxi2, "mingxi3": mingxi3 });
  }
  catch (error) {
    console.log('QueryBaobiaoBenefit error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryBaobiaoBenefitPerFactory', async (req, res) => {
  try {
    let date = new Date();
    let i, j, k, index, begin = -1;
    let array = new Array();
    let mingxi = new Array();
    let mingxi2 = new Array();
    let factory = new Array();
    i = date.getFullYear() - 1;
    date.setFullYear(i, 11, 21); // 从上一年的12月21日开始
    index = date.getTime();
    if (req.body.starttime != undefined) {
      index = Date.parse(req.body.starttime);
      if (isNaN(index))
        index = date.getTime();
    }
    let sql = "select * from machining_union_sheet where lingqu_time != '' and price != '' ORDER BY lingqu_time ASC";
    let suc = await db_util.query(sql);
    for (i = 0; i < suc.length; i++) {
      k = Date.parse(suc[i].lingqu_time);
      if (k >= index) {
        begin = i;
        break;
      }
    }
    if (begin < 0) {
      res.status(200);
      res.json({ "result": "ok", "order": array, "factory": factory, "mingxi": mingxi });
      return;
    }
    /*factory.push("WEKS(P3)");
    factory.push("WAKS(P1)");
    factory.push("WAKS(P5)");
    factory.push("WAKS(6A)");
    factory.push("WAKS(6B)");
    factory.push("其它");*/
    for (i = begin; i < suc.length; i++) {
      for (j = 0; j < factory.length; j++) {
        if (factory[j] == suc[i]['factory'])
          break;
      }
      if (j >= factory.length) {
        factory.push(suc[i]['factory']);
      }
    }
    factory.sort();
    let currentTime = Date.parse(suc[begin].lingqu_time);
    date.setTime(currentTime);
    let first = getOTDWeek(date);
    let currentmonth = first.month;
    let json = {};
    json["month"] = first.month;
    json["month_name"] = first.month_name;
    json["month_range"] = first.month_range;
    json["total"] = 0;
    json["data"] = new Array();
    let json2 = {};
    json2["from"] = first.from;
    json2["to"] = first.to;
    json2["range"] = first.range;
    json2["total"] = 0;
    json2["factory"] = new Array();
    for (j = 0; j < factory.length; j++) {
      let json3 = {};
      json3["name"] = factory[j];
      json3["cost"] = 0;
      json2["factory"].push(json3);
    }
    json["data"].push(json2);
    array.push(json);
    if (suc.length > 0) {
      date.setTime(Date.now());
      let last = getOTDWeek(date);
      endtime = last.to;
      currentmonth = last.month;
      while (suc.length > 0) {
        currentTime += 7 * 24 * 3600 * 1000;
        date.setTime(currentTime);
        first = getOTDWeek(date);
        if (first.to > last.to)
          break;
        for (i = 0; i < array.length; i++) {
          if (array[i]["month"] == first.month) {
            for (k = 0; k < array[i]["data"].length; k++) {
              if (array[i]["data"][k].range == first.range)
                break;
            }
            if (k == array[i]["data"].length) {
              let json2 = {};
              json2["from"] = first.from;
              json2["to"] = first.to;
              json2["range"] = first.range;
              json2["total"] = 0;
              json2["factory"] = new Array();
              for (j = 0; j < factory.length; j++) {
                let json3 = {};
                json3["name"] = factory[j];
                json3["cost"] = 0;
                json2["factory"].push(json3);
              }
              array[i]["data"].push(json2);
            }
            break;
          }
        }
        if (i == array.length) {
          let json = {};
          json["month"] = first.month;
          json["month_name"] = first.month_name;
          json["month_range"] = first.month_range;
          json["total"] = 0;
          json["data"] = new Array();
          let json2 = {};
          json2["from"] = first.from;
          json2["to"] = first.to;
          json2["range"] = first.range;
          json2["total"] = 0;
          json2["factory"] = new Array();
          for (j = 0; j < factory.length; j++) {
            let json3 = {};
            json3["name"] = factory[j];
            json3["cost"] = 0;
            json2["factory"].push(json3);
          }
          json["data"].push(json2);
          array.push(json);
        }
      }
    }
    for (i = begin; i < suc.length; i++) {
      date.setTime(Date.parse(suc[i].lingqu_time));
      first = getOTDWeek(date);
      let quatity = parseInt(suc[i].quatity);
      let cost = quatity * parseFloat(suc[i].price);
      let lingqu_count = 0;
      sql = "select * from delivery_sheet where union_order = '" + suc[i].union_order + "'";
      let suc3 = await db_util.query(sql);
      for (k = 0; k < suc3.length; k++) {
        j = parseInt(suc3[k].quatity);
        if (isNaN(j))
          j = 0;
        lingqu_count += j;
      }
      if (lingqu_count < quatity)
        cost = 0;

      for (j = 0; j < array.length; j++) {
        if (array[j]["month"] == first.month) {
          for (k = 0; k < array[j]["data"].length; k++) {
            if (array[j]["data"][k].range == first.range) {
              for (index = 0; index < array[j]["data"][k].factory.length; index++) {
                if (array[j]["data"][k].factory[index].name == suc[i].factory) {
                  array[j]["data"][k].factory[index].cost += cost;
                  array[j]["data"][k].total += cost;
                  break;
                }
              }
              if (index == array[j]["data"][k].factory.length) {
                index--; // 其它
                array[j]["data"][k].factory[index].cost += cost;
                array[j]["data"][k].total += cost;
              }
              break;
            }
          }
          break;
        }
      }

      let cailiaofei = 0;
      sql = "select * from material_send where union_order = '" + suc[i].union_order + "'";
      let succ2 = await db_util.query(sql);
      for (index = 0; index < succ2.length; index++) {
        cailiaofei += (parseFloat(succ2[index].quatity) * parseFloat(succ2[index].price));
      }
      succ2 = null;
      sql = "select * from material_send where other_order = '" + suc[i].union_order + "'";
      succ2 = await db_util.query(sql);
      for (index = 0; index < succ2.length; index++) {
        cailiaofei += (parseFloat(succ2[index].quatity) * parseFloat(succ2[index].price));
      }
      cailiaofei = dotFixed(cailiaofei);
      cost = quatity * parseFloat(suc[i].price);

      let json = {};
      if (lingqu_count == quatity)
        json["date"] = suc[i].lingqu_time.substr(0, 10);
      else
        json["date"] = suc[i].delivery_date;
      json["unionorder"] = suc[i].union_order;
      json["name"] = suc[i].name;
      json["quatity"] = suc[i].quatity;
      json["apply_persopn"] = suc[i].apply_person;
      json["factory"] = suc[i].factory;
      json["charge_department"] = suc[i].charge_department;
      json["TTL_hour"] = suc[i].total_time;
      json["cost"] = cailiaofei;
      json["price"] = suc[i].price;
      json["total_price"] = cost;
      if (lingqu_count == quatity) // 已结单
        mingxi.push(json);
      else
        AddItemOrderByDate(mingxi2, json);
    }

    for (i = 0; i < array.length; i++) {
      if (array[i]["month"] != currentmonth) {
        array[i]["factory"] = new Array();
        for (j = 0; j < factory.length; j++) {
          let json3 = {};
          json3["name"] = factory[j];
          json3["cost"] = 0;
          array[i]["factory"].push(json3);
        }
        for (k = 0; k < array[i]["data"].length; k++) {
          for (j = 0; j < array[i]["data"][k].factory.length; j++) {
            array[i]["factory"][j]["cost"] += array[i]["data"][k].factory[j]["cost"];
            array[i]["total"] += array[i]["data"][k].factory[j]["cost"];
          }
        }
        for (j = 0; j < array[i]["factory"].length; j++) {
          array[i]["factory"][j]["cost"] = dotFixed(array[i]["factory"][j]["cost"]);
        }
        array[i]["total"] = dotFixed(array[i]["total"]);
        array[i]["data"].length = 0;
      }
      else {
        for (k = 0; k < array[i]["data"].length; k++) {
          for (j = 0; j < array[i]["data"][k].factory.length; j++) {
            array[i]["total"] += array[i]["data"][k].factory[j]["cost"];
          }
        }
        array[i]["total"] = dotFixed(array[i]["total"]);
      }
    }

    res.status(200);
    res.json({ "result": "ok", "order": array, "factory": factory, "mingxi": mingxi, "mingxi2": mingxi2 });
  }
  catch (error) {
    console.log('QueryBaobiaoBenefitPerFactory error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

// 生产排程总计划 FSMS
app.post('/QueryProductionSchedulingPlan', async (req, res) => {
  try {
    let time = 0;
    let date = new Date();
    let array = new Array();
    let sql = "select * from machining_union_sheet where status = 0";
    let suc = await db_util.query(sql);
    for (let i = 0; i < suc.length; i++) {
      let json = {};
      if (suc[i].status == '1')
        json["status"] = "Close";
      else {
        if (suc[i].lingqu_time != '') {
          time = Date.parse(suc[i].lingqu_time);
          if (isNaN(time))
            time = Date.now();
        }
        else {
          time = Date.now();
        }
        date.setTime(time);
        let temp = getMonthDayTime(date, 1);
        if (temp > suc[i].delivery_date)
          json["status"] = "Delay";
        else
          json["status"] = "Ongoing";
      }
      json["factory"] = suc[i].factory;
      json["machine_type"] = suc[i].machine_type;
      json["name"] = suc[i].name;
      json["delivery_date"] = suc[i].delivery_date;
      json["apply_person"] = suc[i].apply_person;
      json["unionorder"] = suc[i].union_order;
      json["design_qixian"] = suc[i].design_end_date;
      json["quatity"] = suc[i].quatity;
      if (suc[i].sheji_endtime == null)
        json["design_endtime"] = "";
      else if (suc[i].sheji_endtime.length > 10)
        json["design_endtime"] = suc[i].sheji_endtime.substr(0, 10);
      else
        json["design_endtime"] = suc[i].sheji_endtime;
      json["code_qixian"] = "";
      if (suc[i].biancheng_endtime == null)
        json["code_endtime"] = "";
      else if (suc[i].biancheng_endtime.length > 10)
        json["code_endtime"] = suc[i].biancheng_endtime.substr(0, 10);
      else
        json["code_endtime"] = suc[i].biancheng_endtime;
      json["jiagong_qixian"] = "";
      if (suc[i].jiagong_endtime == null)
        json["jiagong_endtime"] = "";
      else if (suc[i].jiagong_endtime.length > 10)
        json["jiagong_endtime"] = suc[i].jiagong_endtime.substr(0, 10);
      else
        json["jiagong_endtime"] = suc[i].jiagong_endtime;
      json["ercijg_qixian"] = "";
      if (suc[i].ercijg_endtime == null)
        json["ercijg_endtime"] = "";
      else if (suc[i].ercijg_endtime.length > 10)
        json["ercijg_endtime"] = suc[i].ercijg_endtime.substr(0, 10);
      else
        json["ercijg_endtime"] = suc[i].ercijg_endtime;
      json["zuzhuang_qixian"] = suc[i].assemble_end_date;
      if (suc[i].zuzhuang_endtime == null)
        json["zuzhuang_endtime"] = "";
      else if (suc[i].zuzhuang_endtime.length > 10)
        json["zuzhuang_endtime"] = suc[i].zuzhuang_endtime.substr(0, 10);
      else
        json["zuzhuang_endtime"] = suc[i].zuzhuang_endtime;
      json["machine_remark"] = suc[i].machine_remark;
      json["delay_remark"] = "";
      sql = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and rawdata != 0";
      let succ2 = await db_util.query(sql);
      for (let k = 0; k < succ2.length; k++) {
        if (succ2[k].end_date > json["jiagong_qixian"])
          json["jiagong_qixian"] = succ2[k].end_date;
        //if( succ2[k].code_end_date > json["code_qixian"] )
        json["code_qixian"] = "";//succ2[k].code_end_date;
        if (succ2[k].machine_end_date_2 > json["ercijg_qixian"])
          json["ercijg_qixian"] = succ2[k].machine_end_date_2;
        if (succ2[k].machine_remark != '') {
          if (json["delay_remark"] != '')
            json["delay_remark"] += ";";
          json["delay_remark"] += succ2[k].machine_remark;
        }
        /*if( succ2[k].code_remark != '' )
        {
          if( json["delay_remark"] != '' )
            json["delay_remark"] += ";";
          json["delay_remark"] += succ2[k].code_remark;
        }*/
        if (succ2[k].machine_remark_2 != '') {
          if (json["delay_remark"] != '')
            json["delay_remark"] += ";";
          json["delay_remark"] += succ2[k].machine_remark_2;
        }
      }
      array.push(json);
    }
    array.sort(keysort('delivery_date', false, 'unionorder'));

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryProductionSchedulingPlan error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})
// 设计/编程/二次加工/组装/品检/标准件备料/总检/CNC设备生产进度  FSMS
app.post('/QuerySegmentSchedule', async (req, res) => {
  try {
    let sql = "";
    let array = new Array();
    if (req.body.segment == "design") {
      sql = "select * from machining_union_sheet where status = 0";
      let suc = await db_util.query(sql);
      for (let i = 0; i < suc.length; i++) {
        if (suc[i].stage.charAt(0) == '0') // 已完成
          continue;
        let json = {};
        if (suc[i].engineer == '')
          json["status"] = "待設計";
        else
          json["status"] = "設計中";
        json["factory"] = suc[i].factory;
        json["machine_type"] = suc[i].machine_type;
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["engineer"] = suc[i].engineer;
        json["delivery_date"] = suc[i].delivery_date;
        json["design_qixian"] = suc[i].design_end_date;
        json["design_endtime"] = suc[i].sheji_endtime;
        array.push(json);
      }
    }
    else if (req.body.segment == "code") // 编程改成加工 - 2021/02/19
    {
      sql = "select * from machining_union_sheet where status = 0";
      let suc = await db_util.query(sql);
      for (let i = 0; i < suc.length; i++) {
        if (suc[i].stage.charAt(2) == '0') // 已完成
          continue;
        let json = {};
        json["status"] = "加工中";//"編程中";
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["code_qixian"] = "";
        sql = "select id, end_date, machine_end_date_2 from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and status = 1";
        let succ2 = await db_util.query(sql);
        for (let k = 0; k < succ2.length; k++) {
          if (succ2[k].end_date > json["code_qixian"])
            json["code_qixian"] = succ2[k].end_date;
        }
        array.push(json);
      }
    }
    else if (req.body.segment == "ercijg") {
      let engineer = "";
      sql = "select * from machining_union_sheet where status = 0";
      let suc = await db_util.query(sql);
      for (let i = 0; i < suc.length; i++) {
        if (suc[i].stage.charAt(4) == '0') // 已完成
          continue;
        let json = {};
        json["status"] = "加工中";
        json["ercijg_qixian"] = "";
        sql = "select id, machine_end_date_2, engineer_ercijiagong from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and status = 4";
        let succ2 = await db_util.query(sql);
        for (let k = 0; k < succ2.length; k++) {
          if (succ2[k].machine_end_date_2 > json["ercijg_qixian"])
            json["ercijg_qixian"] = succ2[k].machine_end_date_2;
          if (succ2[k].engineer_ercijiagong != '') {
            if (engineer.length > 0)
              engineer += ",";
            engineer += succ2[k].engineer_ercijiagong;
          }
        }
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["engineer"] = engineer;
        array.push(json);
        engineer = "";
      }
    }
    else if (req.body.segment == "pinjian") {
      sql = "select * from machining_union_sheet where status = 0";
      let suc = await db_util.query(sql);
      let i, j, k;
      for (i = 0; i < suc.length; i++) {
        if (suc[i].stage.charAt(3) == '0') // 已完成
          continue;
        sql = "select * from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "' and status = 3";
        let succ3 = await db_util.query(sql);
        for (k = 0; k < succ3.length; k++) {
          if (succ3[k].songjian_shijian == '')
            continue;
          let json = {};
          json["status"] = "";
          json["check_date"] = succ3[k].songjian_shijian;
          json["box"] = succ3[k].box;
          json["name"] = suc[i].name;
          json["image_no"] = succ3[k].ljmc;
          json["quatity_total"] = succ3[k].gjsl;
          json["status"] = succ3[j].check_status;
          json["ok_count"] = "0";
          json["ng_count"] = "0";
          if (succ3[k].gjjcjg != '') {
            j = succ3[k].gjjcjg.indexOf(',');
            if (j > 0) {
              json["ng_count"] = succ3[k].gjjcjg.slice(0, j);
              json["ok_count"] = succ3[k].gjjcjg.slice(j + 1);
            }
          }
          json["unionorder"] = suc[i].union_order;
          json["delivery_date"] = suc[i].delivery_date;
          if (json["quatity_total"] != json["ok_count"] || json["ng_count"] != "0")
            array.push(json);
        }
      }
    }
    else if (req.body.segment == "zuzhuang") {
      let i, k;
      sql = "select * from machining_union_sheet where status = 0 and stage like '_____1%'";
      let suc = await db_util.query(sql);
      for (i = 0; i < suc.length; i++) {
        sql = "select status from dispatch_sheet where gjsl != '0' and union_order = '" + suc[i].union_order + "'";
        let succ2 = await db_util.query(sql);
        for (k = 0; k < succ2.length; k++) {
          if (succ2[k].status != 5)
            break;
        }
        if (k < succ2.length) // 还有加工件没有到组装阶段
          continue;
        let json = {};
        json["status"] = "組裝中";
        json["zuzhuang_qixian"] = suc[i].assemble_end_date;
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["engineer"] = suc[i].engineer_zuzhuang;
        array.push(json);
      }
    }
    else if (req.body.segment == "zongjian") {
      sql = "select * from machining_union_sheet where status = 0 and lingqu_time = ''";
      let suc = await db_util.query(sql);
      for (let i = 0; i < suc.length; i++) {
        if (suc[i].quatity == suc[i].zongjian_ok_count || suc[i].songjian_time == '')
          continue;
        let json = {};
        json["status"] = "";
        json["songjian_time"] = suc[i].songjian_time;
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["quatity"] = suc[i].quatity;
        json["code19"] = suc[i].code19;
        json["ng_count"] = suc[i].zongjian_ng_count;
        json["ok_count"] = suc[i].zongjian_ok_count;
        json["delivery_date"] = suc[i].delivery_date;
        array.push(json);
      }
    }
    else if (req.body.segment == "beiliao") {
      sql = "select union_order, name, delivery_date from machining_union_sheet where status = 0 and length(engineer) > 0 ORDER BY delivery_date ASC";
      let suc = await db_util.query(sql);
      for (let i = 0; i < suc.length; i++) {
        sql = "select sheet_order, material_no, beiliao_ztai from machining_sheet where quatity != '0' and union_order = '" + suc[i].union_order + "' and type_flag = 0";
        let suc2 = await db_util.query(sql);
        let status1 = 0, status2 = 0, status3 = "";
        for (let k = 0; k < suc2.length; k++) {
          if (suc2[k].beiliao_ztai == 2) {
            status2++;
          }
          else if (suc2[k].beiliao_ztai == 3) {
            if (status3.length > 0)
              status3 += ",";
            status3 += suc2[k]['material_no'];
          }
          else {
            status1++;
          }
        }
        let json = {};
        if (status3.length > 0)
          json["status"] = "缺料";
        else if (status1 > 0)
          json["status"] = "備料中";
        else
          continue;//json["status"] = "已備料";
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["yibei"] = status2;
        json["queliao"] = (suc2.length - status1 - status2);
        json["delivery_date"] = suc[i].delivery_date;
        json["remark"] = status3;
        array.push(json);
      }

      sql = "select * from material_apply where status = 'true'"; // 签核后才显示
      let suc4 = await db_util.query(sql);
      for (let i = 0; i < suc4.length; i++) {
        if (suc4[i].lingliao_riqi != '' || suc4[i].beiliao_ztai == 2)
          continue;
        let json = {};
        if (suc4[i].beiliao_ztai == 3)
          json["status"] = "缺料";
        else if (suc4[i].beiliao_ztai == 2)
          json["status"] = "已備料";
        else
          json["status"] = "備料中";
        json["unionorder"] = suc4[i].applyID;
        json["name"] = suc4[i].name;
        json["yibei"] = suc4[i].yibei_shuliang;
        json["queliao"] = 0;
        json["delivery_date"] = "";
        if (suc4[i]['union_order'] != '') {
          sql = "select id, delivery_date from machining_union_sheet where union_order = '" + suc4[i]['union_order'] + "'";
          let suc2 = await db_util.query(sql);
          if (suc2.length > 0)
            json["delivery_date"] = suc2[0]['delivery_date'];
        }
        json["remark"] = suc4[i]['material_no'];
        let stock = parseInt(suc4[i].stock);
        if (isNaN(stock))
          stock = 0;
        let yibei = parseInt(suc4[i].yibei_shuliang);
        if (isNaN(yibei))
          yibei = 0;
        let tuiku = parseInt(suc4[i].tuiku_shuliang);
        if (isNaN(tuiku))
          tuiku = 0;
        stock += tuiku;
        tuiku = parseInt(suc4[i].quatity);
        if (isNaN(tuiku))
          tuiku = 0;
        if (stock < tuiku)
          json["queliao"] = tuiku - stock;
        array.push(json);
      }
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QuerySegmentSchedule error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryWorkhour', async (req, res) => {
  try {
    let i, j, k;
    let array = new Array();
    let sql = "select remark from cncother where name = 'paiban' GROUP BY remark";
    let suc = await db_util.query(sql);
    for (i = 0; i < suc.length; i++) {
      sql = "select * from cncother where name = 'paiban' and remark = '" + suc[i].remark + "'"
      let succ2 = await db_util.query(sql);
      let json = {};
      json["type"] = suc[i].remark;
      for (k = 0; k < succ2.length; k++) {
        j = parseFloat(succ2[k].value);
        if (isNaN(j))
          j = 0;
        if (json[succ2[k].other] == undefined)
          json[succ2[k].other] = 0;
        json[succ2[k].other] += j;
      }
      array.push(json);
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryWorkhour error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryDailyWorkhour', async (req, res) => {
  try {
    let json = {};
    let sql = "select * from cncother where name = 'workhour'";
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      json["design"] = 20;
      json["code"] = 20;
      json["jiagong"] = 20;
      json["ercijiagong"] = 20;
      json["zuzhuang"] = 20;
      await db_util.query("insert into cncother values ('workhour', '20', 'design', '', '')");
      await db_util.query("insert into cncother values ('workhour', '20', 'code', '', '')");
      await db_util.query("insert into cncother values ('workhour', '20', 'jiagong', '', '')");
      await db_util.query("insert into cncother values ('workhour', '20', 'ercijiagong', '', '')");
      await db_util.query("insert into cncother values ('workhour', '20', 'zuzhuang', '', '')");
    }
    else {
      for (let i = 0; i < suc.length; i++) {
        json[suc[i].remark] = suc[i].value;
      }
    }
    json["result"] = "ok";
    res.status(200);
    res.json(json);
  }
  catch (error) {
    console.log('QueryDailyWorkhour error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/UpdateDailyWorkhour', async (req, res) => {
  try {
    let i = 0;
    let sql = "select * from cncother where name = 'workhour'";
    let suc = await db_util.query(sql);
    if (req.body.design != undefined) {
      for (i = 0; i < suc.length; i++) {
        if (suc[i].remark == 'design')
          break;
      }
      if (i == suc.length)
        sql = "insert into cncother (name, value, remark) values ('workhour', '" + req.body.design + "', 'design')";
      else
        sql = "update cncother set value = '" + req.body.design + "' where name = 'workhour' and remark = 'design'";
      await db_util.query(sql);
    }
    if (req.body.code != undefined) {
      for (i = 0; i < suc.length; i++) {
        if (suc[i].remark == 'code')
          break;
      }
      if (i == suc.length)
        sql = "insert into cncother (name, value, remark) values ('workhour', '" + req.body.code + "', 'code')";
      else
        sql = "update cncother set value = '" + req.body.code + "' where name = 'workhour' and remark = 'code'";
      await db_util.query(sql);
    }
    if (req.body.jiagong != undefined) {
      for (i = 0; i < suc.length; i++) {
        if (suc[i].remark == 'jiagong')
          break;
      }
      if (i == suc.length)
        sql = "insert into cncother (name, value, remark) values ('workhour', '" + req.body.jiagong + "', 'jiagong')";
      else
        sql = "update cncother set value = '" + req.body.jiagong + "' where name = 'workhour' and remark = 'jiagong'";
      await db_util.query(sql);
    }
    if (req.body.ercijiagong != undefined) {
      for (i = 0; i < suc.length; i++) {
        if (suc[i].remark == 'ercijiagong')
          break;
      }
      if (i == suc.length)
        sql = "insert into cncother (name, value, remark) values ('workhour', '" + req.body.ercijiagong + "', 'ercijiagong')";
      else
        sql = "update cncother set value = '" + req.body.ercijiagong + "' where name = 'workhour' and remark = 'ercijiagong'";
      await db_util.query(sql);
    }
    if (req.body.zuzhuang != undefined) {
      for (i = 0; i < suc.length; i++) {
        if (suc[i].remark == 'zuzhuang')
          break;
      }
      if (i == suc.length)
        sql = "insert into cncother (name, value, remark) values ('workhour', '" + req.body.zuzhuang + "', 'zuzhuang')";
      else
        sql = "update cncother set value = '" + req.body.zuzhuang + "' where name = 'workhour' and remark = 'zuzhuang'";
      await db_util.query(sql);
    }

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('UpdateDailyWorkhour error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

function SetTaskItem(date, design, code, jiagong, ercijg, zuzhuang) {
  let json = {};
  json["date"] = date;
  json["design"] = {};
  json["design"]["set_workhour"] = design;
  json["design"]["estimate_hour"] = 0;
  json["design"]["total_hour"] = 0;
  json["design"]["hit"] = false;
  json["design"]["tasks"] = new Array();
  json["code"] = {};
  json["code"]["set_workhour"] = code;
  json["code"]["estimate_hour"] = 0;
  json["code"]["total_hour"] = 0;
  json["code"]["hit"] = false;
  json["code"]["tasks"] = new Array();
  json["jiagong"] = {};
  json["jiagong"]["set_workhour"] = jiagong;
  json["jiagong"]["estimate_hour"] = 0;
  json["jiagong"]["total_hour"] = 0;
  json["jiagong"]["hit"] = false;
  json["jiagong"]["tasks"] = new Array();
  json["ercijiagong"] = {};
  json["ercijiagong"]["set_workhour"] = ercijg;
  json["ercijiagong"]["estimate_hour"] = 0;
  json["ercijiagong"]["total_hour"] = 0;
  json["ercijiagong"]["hit"] = false;
  json["ercijiagong"]["tasks"] = new Array();
  json["zuzhuang"] = {};
  json["zuzhuang"]["set_workhour"] = zuzhuang;
  json["zuzhuang"]["estimate_hour"] = 0;
  json["zuzhuang"]["total_hour"] = 0;
  json["zuzhuang"]["hit"] = false;
  json["zuzhuang"]["tasks"] = new Array();
  return json;
}

//FSMS
app.post('/QueryTasktable', async (req, res) => {
  try {
    let date = new Date();
    let today = getMonthDayTime(date, 1);
    let cost_time = date.getTime();
    let array = new Array();
    let i, j, k, stageValue;
    let design = 0, code = 0;
    let jiagong = 0, ercijg = 0, zuzhuang = 0;
    let sucData = await db_util.query("select * from cncother where name = 'workhour'");
    for (i = 0; i < sucData.length; i++) {
      if (sucData[i].remark == 'design')
        design = parseFloat(sucData[i].value);
      if (sucData[i].remark == 'code')
        code = parseFloat(sucData[i].value);
      if (sucData[i].remark == 'jiagong')
        jiagong = parseFloat(sucData[i].value);
      if (sucData[i].remark == 'ercijiagong')
        ercijg = parseFloat(sucData[i].value);
      if (sucData[i].remark == 'zuzhuang')
        zuzhuang = parseFloat(sucData[i].value);
    }
    for (i = 0; i < 60; i++) {
      date.setTime(cost_time + i * 24 * 3600 * 1000);
      let json = SetTaskItem(getMonthDayTime(date, 1), design, code, jiagong, ercijg, zuzhuang);
      array.push(json);
    }
    let sql = "select * from autoschedule";
    let suc = await db_util.query(sql);
    for (i = 0; i < suc.length; i++) {
      sql = "select status, stage from machining_union_sheet where union_order = '" + suc[i].union_order + "'";
      let suc3 = await db_util.query(sql);
      if (suc3.length == 0)
        continue;
      if (suc3[0].status != '0')
        continue;
      stageValue = 0;
      for (k = 0; k < suc3[0].stage.length; k++) {
        if (suc3[0].stage.charAt(k) != '0') {
          stageValue = k;
          break;
        }
      }
      if (stageValue > 5)
        continue;
      sql = "select * from task_sheet where id = '" + suc[i].id + "' and task != 'code'";
      let suc2 = await db_util.query(sql);
      for (k = 0; k < suc2.length; k++) {
        if (suc2[k].task == "design" && stageValue > 0)
          continue;
        else if (suc2[k].task == "jiagong" && stageValue > 2)
          continue;
        else if (suc2[k].task == "ercijiagong" && stageValue > 4)
          continue;
        for (j = 0; j < array.length; j++) {
          if (array[j]["date"] == suc2[k].date) {
            break;
          }
        }
        if (j >= array.length) {
          let json2 = SetTaskItem(suc2[k].date, design, code, jiagong, ercijg, zuzhuang);
          for (j = 0; j < array.length; j++) {
            if (suc2[k].date < array[j].date) {
              array.splice(j, 0, json2);
              break;
            }
          }
        }
        if (j >= array.length)
          continue;
        sql = suc2[k].task + "_workhour";
        let json = {};
        json["union_order"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["delivery_date"] = suc[i].delivery_date;
        json["quatity"] = suc[i].quatity;
        json["workhour"] = suc2[k].workhour;
        json["date"] = suc2[k].date;
        json["task"] = suc2[k].task;
        json["estimate_workhour"] = suc[i][sql];
        json["total_workhour"] = 0;
        json["Type"] = suc[i]["type"];
        for (let n = 0; n < suc2.length; n++) {
          if (suc2[n].task == suc2[k].task) {
            json["total_workhour"] += parseFloat(suc2[n].workhour);
          }
        }
        array[j][suc2[k].task]["tasks"].push(json);
        array[j][suc2[k].task]["estimate_hour"] = parseFloat(suc[i][sql]);
        array[j][suc2[k].task]["total_hour"] += parseFloat(suc2[k].workhour);
      }
    }
    if (array.length > 60) {
      i = array.length - 60;
      array.splice(60, i);
    }
    res.status(200);
    res.json({ "result": "ok", "order": array, "today": today });
  }
  catch (error) {
    console.log('QueryTasktable error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/AddTask', async (req, res) => {
  try {
    console.log('AddTask', req.body);
    let date = new Date();
    let today = getMonthDayTime(date, 1);
    let body = req.body;
    let design = 0;//, code = 0;
    let jiagong = 0, ercijg = 0, zuzhuang = 0;
    let sucData = await db_util.query("select * from cncother where name = 'workhour'");
    for (let i = 0; i < sucData.length; i++) {
      if (sucData[i].remark == 'design')
        design = parseFloat(sucData[i].value);
      //if( sucData[i].remark == 'code' )
      //  code = parseFloat(sucData[i].value);
      if (sucData[i].remark == 'jiagong')
        jiagong = parseFloat(sucData[i].value);
      if (sucData[i].remark == 'ercijiagong')
        ercijg = parseFloat(sucData[i].value);
      if (sucData[i].remark == 'zuzhuang')
        zuzhuang = parseFloat(sucData[i].value);
    }
    let i, j, k;
    let array = new Array();
    let arrTask = new Array();
    date.setTime(date.getTime() + 5 * 24 * 3600 * 1000);
    let sql = "select id from autoschedule where delivery_date > '" + getMonthDayTime(date, 1) + "'";
    let suc3 = await db_util.query(sql);
    for (i = 0; i < suc3.length; i++) {
      sql = "select * from task_sheet where id = '" + suc3[i].id + "'";
      let suc2 = await db_util.query(sql);
      for (k = 0; k < suc2.length; k++) {
        for (j = 0; j < array.length; j++) {
          if (array[j]["date"] == suc2[k].date) {
            array[j][suc2[k].task] += parseFloat(suc2[k].workhour);
            break;
          }
        }
        if (j == array.length) {
          let json = {};
          json["date"] = suc2[k].date;
          json["design"] = 0;
          json["code"] = 0;
          json["jiagong"] = 0;
          json["ercijiagong"] = 0;
          json["zuzhuang"] = 0;
          json[suc2[k].task] = parseFloat(suc2[k].workhour);
          array.push(json);
        }
      }
    }
    // 20210422：传入参数：name(union_order)/type/delivery_date
    // 20210927: 传入参数: gstype(数组)
    let zuzhuang_workhour = 0, ercijiagong_workhour = 0, jiagong_workhour = 0, design_workhour = 0;
    sql = "select * from cncother where name = 'paiban' and remark = '" + body.type + "'";
    let succ4 = await db_util.query(sql);
    for (i = 0; i < succ4.length; i++) {
      if (body.gstype != undefined) {
        if (body.gstype.length > 0) {
          j = 0;
          for (k = 0; k < body.gstype.length; k++) {
            if (body.gstype[k] == succ4[i]["reserved"]) {
              j = 1;
              break;
            }
          }
          if (j == 0)
            continue;
        }
        else {
          //console.log('AddTask 工时类型数组为空');
        }
      }
      if (succ4[i].other == "design") {
        j = parseFloat(succ4[i].value);
        if (isNaN(j))
          j = 0;
        design_workhour += j;
      }
      else if (succ4[i].other == "work") {
        j = parseFloat(succ4[i].value);
        if (isNaN(j))
          j = 0;
        jiagong_workhour += j;
      }
      else if (succ4[i].other == "workagain") {
        j = parseFloat(succ4[i].value);
        if (isNaN(j))
          j = 0;
        ercijiagong_workhour += j;
      }
      else if (succ4[i].other == "zuzhuang") {
        j = parseFloat(succ4[i].value);
        if (isNaN(j))
          j = 0;
        zuzhuang_workhour += j;
      }
    }
    let endtime = Date.parse(body.delivery_date) - 24 * 3600 * 1000; // 交期的前一天
    date.setTime(endtime);
    if (date.getDay() == 0) // 周日
    {
      endtime -= 24 * 3600 * 1000;
      date.setTime(endtime);
    }
    let taskdate = getMonthDayTime(date, 1);
    // 一、安排组装
    j = zuzhuang_workhour;
    while (true) {
      i = zuzhuang;
      for (k = 0; k < array.length; k++) {
        if (array[k]["date"] == taskdate) {
          i -= array[k]["zuzhuang"];
          break;
        }
      }
      if (i >= j) {
        let json = {};
        json["date"] = taskdate;
        json["task"] = "zuzhuang";
        json["workhour"] = j;
        arrTask.push(json);
        break;
      }
      else {
        if (i > 0) {
          let json = {};
          json["date"] = taskdate;
          json["task"] = "zuzhuang";
          json["workhour"] = i;
          arrTask.push(json);
          j -= i;
        }
        date.setTime(date.getTime() - 24 * 3600 * 1000);
        if (date.getDay() == 0) // 周日
          date.setTime(date.getTime() - 24 * 3600 * 1000);
        taskdate = getMonthDayTime(date, 1);
      }
    }
    if (taskdate <= today) {
      console.log('组装工期不足，最后日期：' + taskdate);
      res.status(200);
      res.json({ "result": "error", "description": "组装工期不足。" });
      return;
    }

    endtime = Date.parse(taskdate) - 24 * 3600 * 1000;
    // 各项任务不可以在同一天
    date.setTime(endtime);
    if (date.getDay() == 0) // 周日
    {
      endtime -= 24 * 3600 * 1000;
      date.setTime(endtime);
    }
    taskdate = getMonthDayTime(date, 1);
    // 二、安排二次加工
    j = ercijiagong_workhour;
    while (true) {
      i = ercijg;
      for (k = 0; k < array.length; k++) {
        if (array[k]["date"] == taskdate) {
          i -= array[k]["ercijiagong"];
          break;
        }
      }
      if (i >= j) {
        let json = {};
        json["date"] = taskdate;
        json["task"] = "ercijiagong";
        json["workhour"] = j;
        arrTask.push(json);
        break;
      }
      else {
        if (i > 0) {
          let json = {};
          json["date"] = taskdate;
          json["task"] = "ercijiagong";
          json["workhour"] = i;
          arrTask.push(json);
          j -= i;
        }
        date.setTime(date.getTime() - 24 * 3600 * 1000);
        if (date.getDay() == 0) // 周日
          date.setTime(date.getTime() - 24 * 3600 * 1000);
        taskdate = getMonthDayTime(date, 1);
      }
    }
    if (taskdate <= today) {
      console.log('二次加工工期不足，最后日期：' + taskdate);
      res.status(200);
      res.json({ "result": "error", "description": "二次加工工期不足。" });
      return;
    }

    endtime = Date.parse(taskdate) - 24 * 3600 * 1000;
    // 各项任务不可以在同一天
    date.setTime(endtime);
    if (date.getDay() == 0) // 周日
    {
      endtime -= 24 * 3600 * 1000;
      date.setTime(endtime);
    }
    taskdate = getMonthDayTime(date, 1);
    // 三、安排加工
    j = jiagong_workhour;
    while (true) {
      i = jiagong;
      for (k = 0; k < array.length; k++) {
        if (array[k]["date"] == taskdate) {
          i -= array[k]["jiagong"];
          break;
        }
      }
      if (i >= j) {
        let json = {};
        json["date"] = taskdate;
        json["task"] = "jiagong";
        json["workhour"] = j;
        arrTask.push(json);
        break;
      }
      else {
        if (i > 0) {
          let json = {};
          json["date"] = taskdate;
          json["task"] = "jiagong";
          json["workhour"] = i;
          arrTask.push(json);
          j -= i;
        }
        date.setTime(date.getTime() - 24 * 3600 * 1000);
        if (date.getDay() == 0) // 周日
          date.setTime(date.getTime() - 24 * 3600 * 1000);
        taskdate = getMonthDayTime(date, 1);
      }
    }
    if (taskdate <= today) {
      console.log('加工工期不足，最后日期：' + taskdate);
      res.status(200);
      res.json({ "result": "error", "description": "加工工期不足。" });
      return;
    }

    /*endtime = Date.parse(taskdate) - 24 * 3600 * 1000;
    // 各项任务不可以在同一天
    date.setTime(endtime);
    if( date.getDay() == 0 ) // 周日
    {
      endtime -= 24 * 3600 * 1000;
      date.setTime(endtime);
    }
    taskdate = getMonthDayTime(date, 1);
    // 四、安排编程
    j = parseFloat(body.code_workhour);
    if( isNaN(j) )
    {
      res.status(200);
      res.json({"result":"error", "description":"编程工时异常。"});
      return;
    }
    while(true)
    {
      i = code;
      for(k=0; k<array.length; k++)
      {
        if( array[k]["date"] == taskdate )
        {
          i -= array[k]["code"];
          break;
        }
      }
      if( i >= j )
      {
        let json = {};
        json["date"] = taskdate;
        json["task"] = "code";
        json["workhour"] = j;
        arrTask.push(json);
        break;
      }
      else
      {
        if( i > 0 )
        {
          let json = {};
          json["date"] = taskdate;
          json["task"] = "code";
          json["workhour"] = i;
          arrTask.push(json);
          j -= i;
        }
        date.setTime(date.getTime() - 24*3600*1000);
        if( date.getDay() == 0 ) // 周日
          date.setTime(date.getTime() - 24*3600*1000);
        taskdate = getMonthDayTime(date, 1);
      }
    }
    if( taskdate <= today )
    {
      console.log('编程工期不足，最后日期：' + taskdate);
      res.status(200);
      res.json({"result":"error", "description":"编程工期不足。"});
      return;
    }*/

    endtime = Date.parse(taskdate) - 24 * 3600 * 1000;
    // 各项任务不可以在同一天
    date.setTime(endtime);
    if (date.getDay() == 0) // 周日
    {
      endtime -= 24 * 3600 * 1000;
      date.setTime(endtime);
    }
    taskdate = getMonthDayTime(date, 1);
    // 五、安排设计
    j = design_workhour;
    while (true) {
      i = design;
      for (k = 0; k < array.length; k++) {
        if (array[k]["date"] == taskdate) {
          i -= array[k]["design"];
          break;
        }
      }
      if (i >= j) {
        let json = {};
        json["date"] = taskdate;
        json["task"] = "design";
        json["workhour"] = j;
        arrTask.push(json);
        break;
      }
      else {
        if (i > 0) {
          let json = {};
          json["date"] = taskdate;
          json["task"] = "design";
          json["workhour"] = i;
          arrTask.push(json);
          j -= i;
        }
        date.setTime(date.getTime() - 24 * 3600 * 1000);
        if (date.getDay() == 0) // 周日
          date.setTime(date.getTime() - 24 * 3600 * 1000);
        taskdate = getMonthDayTime(date, 1);
      }
    }
    if (taskdate <= today) {
      console.log('设计工期不足，最后日期：' + taskdate);
      res.status(200);
      res.json({ "result": "error", "description": "设计工期不足。" });
      return;
    }

    if (body.name == undefined) {
      res.status(200);
      res.json({ "result": "error", "description": "没有设置工单号参数：name=union_order。" });
      return;
    }
    sql = "select * from machining_union_sheet where union_order = '" + body.name + "'";
    let suc2 = await db_util.query(sql);
    if (suc2.length == 0) {
      res.status(200);
      res.json({ "result": "error", "description": "输入的工单号不存在。" });
      return;
    }
    sql = "select * from autoschedule where union_order = '" + suc2[0].union_order + "'";
    let suc = await db_util.query(sql);
    if (suc.length > 0) {
      res.status(200);
      res.json({ "result": "error", "description": "同工单号的治具名称已存在。" });
      return;
    }
    else {
      sql = "insert into autoschedule values(null, '" + suc2[0].union_order + "', '" + suc2[0].name + "', '" + body.type + "',\
            '"+ body.delivery_date + "', '" + body.delivery_date + "', '" + suc2[0].quatity + "', '" + design_workhour + "', '0',\
            '"+ jiagong_workhour + "', '" + ercijiagong_workhour + "', '" + zuzhuang_workhour + "')";
    }
    let suc4 = await db_util.query(sql);
    if (suc4.affectedRows > 0) {
      for (i = 0; i < arrTask.length; i++) {
        design = dotFixed(arrTask[i]["workhour"]);
        sql = "insert into task_sheet values ('" + suc4.insertId + "', '" + arrTask[i]["task"] + "', '" + arrTask[i]["date"] + "', '" + design + "')";
        await db_util.query(sql);
      }
    }

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('AddTask error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/DeleteTask', async (req, res) => {
  try {
    let sql = "select id from autoschedule where union_order = '" + req.body.unionorder + "'";
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      res.status(200);
      res.json({ "result": "ok", "description": "the unionorder does not exist" });
      return;
    }
    sql = "delete from task_sheet where id = '" + suc[0].id + "'";
    await db_util.query(sql);
    sql = "delete from autoschedule where id = '" + suc[0].id + "'";
    await db_util.query(sql);

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('DeleteTask error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/UpdateTask', async (req, res) => {
  if (req.body.date == undefined || req.body.task == undefined) {
    res.status(200);
    res.json({ "result": "error", "description": "not find the date or task" });
    return;
  }
  try {
    let sql = "select * from autoschedule where union_order = '" + req.body.unionorder + "'";
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      res.status(200);
      res.json({ "result": "error", "description": "not find the name" });
      return;
    }
    let where = " where id = '" + suc[0].id + "' and task = '" + req.body.task + "' and date = '" + req.body.date + "'";
    if (req.body.dateNew != undefined && req.body.dateNew != req.body.date) {
      var workhour = 0;
      if (req.body.workhour != undefined) {
        workhour = parseFloat(req.body.workhour);
      }
      else {
        sql = "select workhour from task_sheet" + where;
        let suc2 = await db_util.query(sql);
        if (suc2.length > 0)
          workhour = parseFloat(suc2[0].workorder);
      }
      sql = "delete from task_sheet" + where;
      await db_util.query(sql);
      where = " where id = '" + suc[0].id + "' and task = '" + req.body.task + "' and date = '" + req.body.dateNew + "'";
      sql = "select workhour from task_sheet" + where;
      let suc3 = await db_util.query(sql);
      if (suc3.length == 0) {
        sql = "insert into task_sheet values ('" + suc[0].id + "', '" + req.body.task + "', '" + req.body.dateNew + "', '" + workhour + "')";
      }
      else {
        workhour += parseFloat(suc3[0].workhour);
        sql = "update task_sheet set workhour = '" + workhour + "'" + where;
      }
      let suc4 = await db_util.query(sql);
      if (suc4.affectedRows == 0) {
        console.log('failed: ' + sql);
      }
    }
    else if (req.body.workhour != undefined) {
      sql = "update task_sheet set workhour = '" + req.body.workhour + "'" + where;
      await db_util.query(sql);
      console.log(sql);
    }
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('UpdateTask error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//NOUSE
app.post('/QueryAlarmInfo', async (req, res) => {
  try {
    var cost_time = 0;
    var date = new Date();
    var hour = date.getHours();
    if (hour < 8) {
      setTime(date, 0);
      cost_time = date.getTime() - 4 * 3600 * 1000;
    }
    else if (hour < 20) // 白班
    {
      setTime(date, 8);
      cost_time = date.getTime();
    }
    else {
      setTime(date, 20);
      cost_time = date.getTime();
    }
    if (req.body.starttime != undefined)
      cost_time = Date.parse(req.body.starttime);
    var array = new Array();
    var sql = "select * from cncalarm where name = 'alarm-" + req.body.MachineName + "' and Time >= '" + cost_time + "' and reason != ''";
    let suc = await db_util.query(sql);
    for (var i = 0; i < suc.length; i++) {
      var json = {};
      json["reason"] = suc[i].alarmMsg;
      json["time"] = suc[i].alarmTime;
      json["reply"] = suc[i].reason;
      json["pic"] = suc[i].pic;
      array.push(json);
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryAlarmInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryChargeDeptInfo', async (req, res) => {
  try {
    let array = new Array();
    let sql = "select * from p79_tofsms GROUP BY ChargeDept";
    let suc = await db_util.query(sql);
    for (let i = 0; i < suc.length; i++) {
      array.push(suc[i].ChargeDept);
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryChargeDeptInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryZhuangjiaInfo', async (req, res) => {
  try {
    let flag = false;
    let array = new Array();
    let sql = "select * from cncother where name = 'zhuangjia'"; // remark：装夹方式 reserved：一种方式下的不同内容
    let suc = await db_util.query(sql);
    for (let i = 0; i < suc.length; i++) {
      flag = false;
      for (let k = 0; k < array.length; k++) {
        if (array[k].mode == suc[i].remark) {
          let json = {};
          json["name"] = suc[i].reserved;
          json["value"] = suc[i].value;
          array[k].time.push(json);
          flag = true;
          break;
        }
      }
      if (flag == false) {
        let json = {};
        json["mode"] = suc[i].remark;
        json["time"] = new Array();
        let json2 = {};
        json2["name"] = suc[i].reserved;
        json2["value"] = suc[i].value;
        json["time"].push(json2);
        array.push(json);
      }
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryZhuangjiaInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

async function AddZhuangjia(name, value, mode) {
  if (name == undefined || value == undefined)
    return;
  let condition = "name = 'zhuangjia' and remark = '" + mode + "' and reserved = '" + name + "'";
  let sql = "select * from cncother where " + condition;
  let suc = await db_util.query(sql);
  if (suc.length > 0) {
    sql = "update cncother set value = '" + value + "' where " + condition;
    await db_util.query(sql);
  }
  else {
    sql = "insert into cncother values ('zhuangjia', '" + value + "', '" + mode + "', '" + name + "', '')";
    await db_util.query(sql);
  }
}

//FSMS
app.post('/AddZhuangjiaInfo', async (req, res) => {
  if (req.body.mode == undefined || req.body.name1 == undefined || req.body.newValue1 == undefined) {
    console.log('AddZhuangjiaInfo: zhuangjia/mode/name/value undefined')
    res.status(200);
    res.json({ "result": "error", "description": "mode/name/value undefined" });
    return;
  }
  try {
    await AddZhuangjia(req.body.name1, req.body.newValue1, req.body.mode);
    await AddZhuangjia(req.body.name2, req.body.newValue2, req.body.mode);
    await AddZhuangjia(req.body.name3, req.body.newValue3, req.body.mode);
    await AddZhuangjia(req.body.name4, req.body.newValue4, req.body.mode);
    await AddZhuangjia(req.body.name5, req.body.newValue5, req.body.mode);
    await AddZhuangjia(req.body.name6, req.body.newValue6, req.body.mode);

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('AddZhuangjiaInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/DeleteZhuangjiaInfo', async (req, res) => {
  try {
    let sql = "delete from cncother where name = 'zhuangjia' and remark = '" + req.body.mode + "'";
    console.log(sql);
    await db_util.query(sql);

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('DeleteZhuangjiaInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryYunyingCostInfo', async (req, res) => {
  try {
    let flag = false;
    let array = new Array();
    let sql = "select * from cncother where name = 'yunying'"; // remark：名称 reserved：月份 other：周
    if (req.body.month != undefined && req.body.month != '')
      sql += " and reserved = '" + req.body.month + "'";
    if (req.body.week != undefined && req.body.week != '')
      sql += " and other = '" + req.body.week + "'";
    sql += " ORDER BY reserved ASC";
    let suc = await db_util.query(sql);
    for (let i = 0; i < suc.length; i++) {
      flag = false;
      for (let k = 0; k < array.length; k++) {
        if (array[k].month == suc[i].reserved) {
          if (array[k].week == suc[i].other) {
            let json2 = {};
            json2["name"] = suc[i].remark;
            json2["value"] = suc[i].value;
            array[k].data.push(json2);
            flag = true;
            break;
          }
        }
      }
      if (flag == false) {
        let json = {};
        json["month"] = suc[i].reserved;
        json["week"] = suc[i].other;
        json["data"] = new Array();
        let json2 = {};
        json2["name"] = suc[i].remark;
        json2["value"] = suc[i].value;
        json["data"].push(json2);
        array.push(json);
      }
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryYunyingCostInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

async function UpdateYunyingCost(name, value, month, week) {
  if (value == undefined || month == undefined) {
    //console.log('UpdateYunyingCostInfo: month or value is undefined');
    return;
  }
  let where = " where name = 'yunying' and remark = '" + name + "' and reserved = '" + month + "'";
  if (week != undefined && week != '')
    where += " and other = '" + week + "'";
  let sql = "select * from cncother" + where;
  let suc = await db_util.query(sql);
  if (suc.length > 0) {
    sql = "update cncother set value = '" + value + "'" + where;
  }
  else {
    if (week != undefined && week != '')
      sql = "insert into cncother values ('yunying', '" + value + "', '" + name + "', '" + month + "', '" + week + "')";
    else
      sql = "insert into cncother values ('yunying', '" + value + "', '" + name + "', '" + month + "', '')";
  }
  await db_util.query(sql);
}

//FSMS
app.post('/UpdateYunyingCostInfo', async (req, res) => {
  let body = req.body;
  try {
    if (body.week != undefined && body.week != '') // 周数据
    {
      await UpdateYunyingCost('dlhours', body.dlhours, body.month, body.week);
      await UpdateYunyingCost('idlhours', body.idlhours, body.month, body.week);
      await UpdateYunyingCost('other', body.other, body.month, body.week);
    }
    else {
      await UpdateYunyingCost('dlperson', body.dlperson, body.month);
      await UpdateYunyingCost('dlhumancost', body.dlhumancost, body.month);
      await UpdateYunyingCost('dlovertime', body.dlovertime, body.month);
      await UpdateYunyingCost('idlperson', body.idlperson, body.month);
      await UpdateYunyingCost('idlhumancost', body.idlhumancost, body.month);
      await UpdateYunyingCost('idlovertime', body.idlovertime, body.month);
      await UpdateYunyingCost('depreciation', body.depreciation, body.month);
      await UpdateYunyingCost('rent', body.rent, body.month);
      await UpdateYunyingCost('sdcharge', body.sdcharge, body.month);
    }

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('UpdateYunyingCostInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryPaibanInfo', async (req, res) => {
  try {
    console.log('QueryPaibanInfo', req.body);
    let flag = false;
    let array = new Array();
    let sql = "select * from cncother where name = 'paiban'"; // remark：治具类型；reserved：工时类型；other：名称（设计/加工/二次加工/组装）
    let suc = await db_util.query(sql);
    let mode = "";
    if (req.body.mode != undefined)
      mode = req.body.mode;
    let timetype = "";
    if (req.body.timetype != undefined)
      timetype = req.body.timetype;
    for (let i = 0; i < suc.length; i++) {
      if (mode != "") {
        if (suc[i].remark.indexOf(mode) < 0)
          continue;
      }
      if (timetype != "") {
        if (suc[i].reserved.indexOf(timetype) < 0)
          continue;
      }
      flag = false;
      for (let k = 0; k < array.length; k++) {
        if (array[k].mode == suc[i].remark) {
          for (let j = 0; j < array[k].type.length; j++) {
            if (array[k].type[j].type == suc[i].reserved) {
              let json = {};
              json["name"] = suc[i].other;
              json["value"] = suc[i].value;
              array[k].type[j].time.push(json);
              flag = true;
              break;
            }
          }
          if (flag == false) {
            let json2 = {};
            json2["type"] = suc[i].reserved;
            json2["time"] = new Array();
            let json = {};
            json["name"] = suc[i].other;
            json["value"] = suc[i].value;
            json2["time"].push(json);
            array[k].type.push(json2);
            flag = true;
            break;
          }
        }
      }
      if (flag == false) {
        let json = {};
        json["mode"] = suc[i].remark;
        json["type"] = new Array();
        let json2 = {};
        json2["type"] = suc[i].reserved;
        json2["time"] = new Array();
        let json3 = {};
        json3["name"] = suc[i].other;
        json3["value"] = suc[i].value;
        json2["time"].push(json3);
        json["type"].push(json2);
        array.push(json);
      }
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryPaibanInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

async function AddPaiban(mode, timetype, name, value) {
  if (name == undefined || value == undefined)
    return;
  let condition = "name = 'paiban' and remark = '" + mode + "' and reserved = '" + timetype + "' and other = '" + name + "'";
  let sql = "select * from cncother where " + condition;
  let suc = await db_util.query(sql);
  if (suc.length > 0) {
    sql = "update cncother set value = '" + value + "' where " + condition;
    await db_util.query(sql);
  }
  else {
    sql = "insert into cncother values ('paiban', '" + value + "', '" + mode + "', '" + timetype + "', '" + name + "')";
    await db_util.query(sql);
  }
}

//FSMS
app.post('/AddPaibanInfo', async (req, res) => {
  if (req.body.mode == undefined || req.body.timetype == undefined || req.body.name1 == undefined || req.body.newValue1 == undefined) {
    console.log('AddPaibanInfo: Paiban/mode/timetype/name1/newValue1 undefined')
    res.status(200);
    res.json({ "result": "error", "description": "mode/timetype/name1/newValue1 undefined" });
    return;
  }
  try {
    // mode：治具类型；timetype：工时类型；name：名称（设计/加工/二次加工/组装）；value：值
    await AddPaiban(req.body.mode, req.body.timetype, req.body.name1, req.body.newValue1);
    await AddPaiban(req.body.mode, req.body.timetype, req.body.name2, req.body.newValue2);
    await AddPaiban(req.body.mode, req.body.timetype, req.body.name3, req.body.newValue3);
    await AddPaiban(req.body.mode, req.body.timetype, req.body.name4, req.body.newValue4);

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('AddPaibanInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/DeletePaibanInfo', async (req, res) => {
  try {
    let sql = "delete from cncother where name = 'paiban' and remark = '" + req.body.mode + "' and reserved = '" + req.body.timetype + "'";
    console.log(sql);
    await db_util.query(sql);

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('DeletePaibanInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/QueryBeizhuInfo', async (req, res) => {
  try {
    let sql = "select * from cncother where name = 'beizhu'";
    let array = new Array();
    let suc = await db_util.query(sql);
    for (let i = 0; i < suc.length; i++) {
      let json = {};
      json["name"] = suc[i].value;
      array.push(json);
    }

    res.status(200);
    res.json({ "result": "ok", "order": array });
  }
  catch (error) {
    console.log('QueryBeizhuInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/AddBeizhuInfo', async (req, res) => {
  try {
    let sql = "";
    if (req.body.oldname != undefined) {
      sql = "select * from cncother where name = 'beizhu' and value = '" + req.body.oldname + "'";
      let suc = await db_util.query(sql);
      if (suc.length > 0)
        sql = "update cncother set value = '" + req.body.name + "' where name = 'beizhu' and value = '" + req.body.oldname + "'";
    }
    if (sql == '') {
      sql = "select * from cncother where name = 'beizhu' and value = '" + req.body.name + "'";
      let suc = await db_util.query(sql);
      if (suc.length == 0)
        sql = "insert into cncother (name, value) values ('beizhu', '" + req.body.name + "')";
      else
        sql = "";
    }
    if (sql != '')
      await db_util.query(sql);
    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('AddBeizhuInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/DeleteBeizhuInfo', async (req, res) => {
  try {
    let sql = "delete from cncother where name = 'beizhu' and value = '" + req.body.name + "'";
    await db_util.query(sql);

    res.status(200);
    res.json({ "result": "ok" });
  }
  catch (error) {
    console.log('DeleteBeizhuInfo error: ' + error.message);
    res.status(200);
    res.json({ "result": "error", "description": error.message });
  }
})

//FSMS
app.post('/SendEmail',async(req, res)=>{

  // let mailParams = {
  //   "type": 'S4',l
  //   "WorkOrder": "WRKS202301060001",
  //   "emp"：["","",""],
  //   "empAddress":["","",""]
  // }
  let subject = '';
  let title ='';
  let mailTo='';
  let mailCc='';
  let type = req.body.type;
  let WorkOrder = req.body.WorkOrder;
  let factory = req.body.factory;
  let name = req.body.name;
  let machine_type = req.body.machine_type;
  let quantity = req.body.quantity;
  let toolway = req.body.toolway;
  let delivery_date = req.body.delivery_date;


  if (type == 'S1') {
    subject = config.mail.subjectS1;
    title = config.mail.titleS1;
    console.log('部門主管');
    mailTo = await getAddress('部門主管');
  }
  if (type == 'S2') {
    subject = config.mail.subjectS2;
    title = config.mail.titleS2;
    console.log('指派工程師');
    mailTo = req.body.empAddress.join(',');
    console.log('部門主管');
    mailCc = await getAddress('部門主管');
  }
  if (type == 'S3') {
    subject = config.mail.subjectS3;
    title = config.mail.titleS3;
    console.log('編程工程師');
    mailTo = await getAddress('編程工程師');
    console.log('部門主管');
    mailCc = await getAddress('部門主管');
  }
  if (type == 'S4') {
    subject = config.mail.subjectS4;
    title = config.mail.titleS4;
    console.log('質檢員');
    mailTo = await getAddress('質檢員');
    console.log('部門主管');
    mailCc = await getAddress('部門主管');
  }
  if (type == 'S5') {
    subject = config.mail.subjectS5;
    title = config.mail.titleS5;
    console.log('組裝員');
    mailTo = await getAddress('組裝員');
    console.log('部門主管');
    mailCc = await getAddress('部門主管');

  }

  if (type == 'S6') {
    subject = config.mail.subjectS6;
    title = config.mail.titleS6;
    console.log('組裝員');
    mailTo = await getAddress('組裝員');
    console.log('部門主管');
    mailCc = await getAddress('部門主管');
  }

  let body = title +
  '<html>' +
  '<body>'+
  '<div>' +
  '<table border="1" cellspacing="0">' +
  '<tr style=\'background:#4483ef;color:white;white-space: nowrap;text-align: center;\'>'

  if(type == 'S4'){
    body += '<td>' + config.mail.WorkOrder_title + '</td>' +
    '<td>' + config.mail.name_title + '</td>' +
    '<td>' + config.mail.machine_type_title + '</td></tr>'+
    '<td>' + WorkOrder + '</td>' +
    '<td>' + name + '</td>' +
    '<td>' + machine_type + '</td></tr>'
  }

  if(type == 'S2' || type == 'S3'){
    body += '<td>' + config.mail.WorkOrder_title + '</td>' +
    '<td>' + config.mail.factory_title + '</td>' +
    '<td>' + config.mail.name_title + '</td>' +
    '<td>' + config.mail.machine_type_title + '</td>' +
    '<td>' + config.mail.quantity_title + '</td>' +
    '<td>' + config.mail.toolway_title + '</td>' +
    '<td>' + config.mail.delivery_date_title + '</td></tr>'+
    '<td>' + WorkOrder + '</td>' +
    '<td>' + name + '</td>' +
    '<td>' + factory + '</td>' +
    '<td>' + machine_type + '</td>' +
    '<td>' + quantity + '</td>' +
    '<td>' + toolway + '</td>' +
    '<td>' + delivery_date + '</td></tr>'
  }

  if(type == 'S1' || type == 'S5' || type == 'S6'){
    body += '<td>' + config.mail.WorkOrder_title + '</td>' +
    '<td>' + config.mail.factory_title + '</td>' +
    '<td>' + config.mail.name_title + '</td>' +
    '<td>' + config.mail.machine_type_title + '</td>' +
    '<td>' + config.mail.quantity_title + '</td>' +
    '<td>' + config.mail.delivery_date_title + '</td></tr>'+
    '<td>' + WorkOrder + '</td>' +
    '<td>' + name + '</td>' +
    '<td>' + factory + '</td>' +
    '<td>' + machine_type + '</td>' +
    '<td>' + quantity + '</td>' +
    '<td>' + delivery_date + '</td></tr>'
  }


  '</table>' +
  '</div>' +
  '</body>' +
  '</html>'

  fs.writeFileSync(`./${WorkOrder}-${type}.html`, body)

  const smtpTransport = nodemailer.createTransport({
    host: config.mail.host,
    secureConnection: false,
    secure: false,
    port: config.mail.port,
  });

  smtpTransport.sendMail({
    from: config.mail.from,
    to: mailTo,
    cc: mailCc,
    bcc: config.mail.bcc,
    subject: subject,//邮件主题
    html: body,
    priority: "high",
  }, function (err) {
    if (err) {
      console.log(err);
      res.json({ "result": "ng" });


    } else {
      console.log(`發送郵件成功！`);
      res.json({ "result": "ok" });
    }
  });

})

/**
 * 
 * @param {*} job 職位
 * @returns 郵件地址
 */
async function getAddress(job){
  let mailList =[];
  let sql = "select * from employee where 1=1";
  let empList = await db_util.query(sql);
  empList.filter(item => item.remark.includes(job))
  .map(item => {
    if (item.mail !== '') {
     mailList.push(item.mail);
    }
  });
  console.log(mailList);
  mailTo = mailList.join(',');

return mailTo;
}

var httpServer = http.createServer(function (req, res) {
  let url = decodeURI(req.url);
  if (req.method.toUpperCase() == "GET") {
    let index = url.lastIndexOf('/');
    let fileName = url.substr(index + 1);
    let filePath = "./public" + url;
    try {
      let stats = fs.statSync(filePath);
      if (stats.isFile()) {
        res.writeHead(200, {
          "Content-type": "application/octet-stream",
          "Content-Disposition": "attachment;filename=" + encodeURI(fileName),
          "Content-Length": stats.size
        });
        let fReadStream = fs.createReadStream(filePath);
        fReadStream.on("data", function (chunk) { res.write(chunk, "binary") });
        fReadStream.on("end", function () { res.end() });
      }
      else {
        if (fileName.length > 0)
          console.log('Download file ' + filePath + ', but cannot find it!');
        res.writeHead(200, { "Content-type": "text/html" });
        res.write("file not exist!");
        res.end();
      }
    }
    catch (err) {
      res.writeHead(200, { "Content-type": "text/html" });
      res.write(err.message);
      res.end();
    }
  }
});

async function intervalFunc() {
  if (g_cncInfo == undefined)
    return;
  if (g_cncInfo.length < 1) {
    loadCNC();
    return;
  }
  let date = new Date();
  let hour = date.getHours();
  if (date.getDate() == 1 && hour < 3 && hour >= 0) {
    try {
      let dt = new Date(date);
      let year = dt.getFullYear();
      let mon = dt.getMonth();
      dt.setMonth(mon - 1);
      let month = getMonthDayTime(dt);
      let sql = "select * from cncmonth where month = '" + month + "' and name = ''";
      let suc = await db_util.query(sql);
      if (suc.length > 0 && suc[0].last_id.length == 0)
        return;
      let starttime = month + '-01 00:00:00';
      let endtime = year + '-';
      if (mon < 9)
        endtime += '0' + (mon + 1) + '-01 00:00:00';
      else
        endtime += (mon + 1) + '-01 00:00:00';
      let ret = await StatisticOee(undefined, starttime, endtime);
      if (ret["result"] == "ok") {
        if (suc.length == 0)
          sql = "insert into cncmonth (month, oee, oee15, run_time, total_time, total_time_15, last_time, last_id) values('" + month + "', '" + ret["oee1"] + "', '" + ret["oee15"] + "', '" + ret["run_time"] + "', '" + ret["total_time"] + "', '" + ret["total_time_15"] + "', '" + ret["last_time"] + "', '')";
        else
          sql = "update cncmonth set oee = '" + ret["oee1"] + "', oee15 = '" + ret["oee15"] + "', run_time = '" + ret["run_time"] + "', total_time = '" + ret["total_time"] + "', total_time_15 = '" + ret["total_time_15"] + "', last_time = '" + ret["last_time"] + "', last_id = '' where month = '" + month + "'";
        await db_util.query(sql);

        sql = "delete from cncmonth where month = '" + month + "' and length(name) > 0";
        await db_util.query(sql);
        if (ret["order"] != undefined) {
          for (let i = 0; i < ret["order"].length; i++) {
            sql = "insert into cncmonth values('" + month + "', '" + g_cncInfo[i].MachineName + "', '" + ret["order"][i]["oee1"] + "', '" + ret["order"][i]["oee15"] + "', '" + ret["order"][i]["run_time"] + "', '" + ret["order"][i]["total_time"] + "', '" + ret["order"][i]["total_time_15"] + "', '" + ret["order"][i]["last_time"] + "', '')";
            await db_util.query(sql);
          }
        }

        dt.setMonth(dt.getMonth() - 5);
        month = getMonthDayTime(dt);
        endtime = month + '-01 00:00:00';
        sql = "delete from cncdata where fmtTime < '" + endtime + "'";
        await db_util.query(sql);
        console.log('清除6个月之前的数据', sql);
      }
    }
    catch (error) {
      console.log('save month data error: ' + error.message);
    }
  }

  if (date.getDay() == 0 && hour >= 0 && hour < 2) {
    let week = getYearWeek(date.getTime() - 5 * 3600 * 1000);
    let sql = "select * from cncother where name = 'cncweek'";
    try {
      let flag = true;
      let suc = await db_util.query(sql);
      if (suc.length > 0) {
        if (suc[0].value == week)
          flag = false;
      }
      if (flag) {
        let dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
        let currTime = dt.getTime();
        dt.setTime(currTime - 7 * 24 * 3600 * 1000);
        let starttime = getMonthDayTime(dt, 1, 1);
        dt.setTime(currTime - 1);
        let endtime = getMonthDayTime(dt, 1, 1);
        let ret = await StatisticOeeWeek(null, starttime, endtime);
        if (ret.length > 0) {
          if (suc.length > 0)
            sql = "update cncother set value = '" + week + "' where name = 'cncweek'";
          else
            sql = "insert into cncother (name, value) values('cncweek', '" + week + "')";
          await db_util.query(sql);
        }
      }
    }
    catch (error) {
      console.log('save week data error: ' + error.message);
    }
  }

  // 检查是否有文件过期需要删除
  if (hour > 0 && hour < 3) {
    let sql = "select * from machining_files where length(union_order) > 10";
    try {
      let temp = 0;
      let days = parseInt(db_util.config.file_lifetime);
      if (isNaN(days))
        days = 365;
      else if (days < 30)
        days = 30;
      days = days * 24 * 3600 * 1000;
      let currentTime = Date.now();
      let suc = await db_util.query(sql);
      for (let i = 0; i < suc.length; i++) {
        temp = Date.parse(suc[i].upload_time);
        if (isNaN(temp))
          continue;
        temp += days;
        if (temp > currentTime)
          continue;
        sql = suc[i].file_path;
        if (fs.existsSync(sql)) {
          fs.unlink(sql, function (err) {
            if (err) {
              console.log('Check file lifetime: failed to delete file: ' + sql);
            }
            else {
              console.log('Check file lifetime: succeeded to delete file: ' + sql);
            }
          });
        }
        temp = sql.lastIndexOf('.');
        if (temp < 1)
          continue;
        let ext = sql.substr(temp + 1).toLowerCase();
        if (ext != 'xlsx' && ext != 'xls')
          continue;
        sql = "./public/" + suc[i].union_order + "/images";
        if (fs.existsSync(sql) == false)
          continue;
        fs.readdirSync(sql).forEach(function (file) {
          ext = sql + "/" + file;
          if (fs.statSync(ext).isDirectory() == false) {
            fs.unlinkSync(ext);
          }
        });
      }
    }
    catch (error) {
      console.log('check file lifetime error: ' + error.message);
    }
  }

  //if( date.getDay() == 0 && hour > 21 )
  if ((date.getTime() - g_lastUpdateTime) > g_nWaitTime && g_cncInfo[0].reserved2 != 88) {
    g_cncInfo[0].reserved2 = 88;
    try {
      let id = 0;
      let ret = await db_util.query("select * from cncother where name = 'checkid'");
      if (ret.length > 0) {
        id = parseInt(ret[0].value);
        if (isNaN(id))
          id = 0;
        else if (id < 1)
          id = 0;
      }
      let sql = "";
      let checkid = 2147483647;
      let cost_time = date.getTime();
      let wait_time = g_nOffTime * 8 / 10;
      let total_count = 0;
      for (let i = 0; i < g_cncInfo.length; i++) {
        sql = "select id, evt_type, Time, Operation_Mode, operatingstatus, operatingmode, alarmstatus from cncdata where MachineName = '" + g_cncInfo[i].MachineName + "'";
        if (id > 0)
          sql += " and id >= '" + id + "'";
        let currentTime = 0;
        let initialTime = 0;
        let last_time = 0;
        let last_evt_type = "";
        let last_mode = "";
        let last_status = "";
        let last_operMode = "";
        let last_alarm = "";
        let count = 0;
        let array = new Array();
        let suc = await db_util.query(sql);
        if (suc.length > 20) {
          for (let k = 0; k < suc.length; k++) {
            currentTime = parseInt(suc[k].Time);
            if (last_time == 0 || currentTime > (last_time + 21000) || last_evt_type != suc[k].evt_type ||
              last_mode != suc[k].Operation_Mode || last_status != suc[k].operatingstatus ||
              last_operMode != suc[k].operatingmode || last_alarm != suc[k].alarmstatus) {
              initialTime = currentTime;
              last_evt_type = suc[k].evt_type;
              last_mode = suc[k].Operation_Mode;
              last_status = suc[k].operatingstatus;
              last_operMode = suc[k].operatingmode;
              last_alarm = suc[k].alarmstatus;
            }
            else if (currentTime > (initialTime + wait_time)) // 这个不删，免得误以为是超时停机
            {
              initialTime = currentTime;
            }
            else if ((k + 1) < suc.length) // 最后一条不要删除
            {
              count++;
              array.push(suc[k].id);
              if (array.length >= 512) {
                sql = "delete from cncdata where id in (";
                for (let j = 0; j < array.length; j++) {
                  if (j > 0)
                    sql += ",";
                  sql += "'" + array[j] + "'";
                }
                sql += ")";
                await db_util.query(sql);
                total_count += array.length;
                array.length = 0;
              }
            }
            last_time = currentTime;
          }
          if (array.length > 0) {
            sql = "delete from cncdata where id in (";
            for (let j = 0; j < array.length; j++) {
              if (j > 0)
                sql += ",";
              sql += "'" + array[j] + "'";
            }
            sql += ")";
            await db_util.query(sql);
            total_count += array.length;
          }
          console.log(g_cncInfo[i].MachineName + ': ' + count + '/' + suc.length + ' = ' + parseInt(count * 100 / suc.length));
          if (suc[suc.length - 1].id < checkid) {
            checkid = suc[suc.length - 1].id;
          }
        }
      }
      if (checkid > id && checkid < 2147483647) {
        if (ret.length > 0)
          sql = "update cncother set value = '" + checkid + "' where name = 'checkid'";
        else
          sql = "insert into cncother (name, value) values('checkid', '" + checkid + "')";
        await db_util.query(sql);
        console.log(sql);
      }
      cost_time = Date.now() - cost_time;
      if (checkid < 2147483647)
        console.log('数据检查结束，删除数据' + total_count + '条，用时' + cost_time);
    }
    catch (error) {
      console.log('压缩数据出错：' + error.message);
    }
    g_cncInfo[0].reserved2 = 8;
  }
}

// 2021/03/16 删除工具统计功能函数：StatisticTool以及intervalAlarm中刀具累计使用时间统计部分的代码

let request = require('request');
const { json } = require('express');
const { log } = require('console');

let sendHttpRequest = function (uri, data) {
  return new Promise((resolve, reject) => {
    //定义请求消息url和头部
    let options = {
      uri: '',
      method: 'POST',
      timeout: 3000,
      headers: {
        'Content-type': 'application/json;charset=UTF-8',
        'Content-Length': Buffer.byteLength(data)
      },
      body: data
    };
    options["uri"] = uri;
    request(options, (err, response, body) => {
      if (err) {
        reject(err);
      }
      else {
        if (body["replyUserId"] != undefined)
          console.log(body);
        resolve(body);
      }
    });
  });
}

async function execute_http_request(index, msg, level, time, name) {
  //定义消息body eventName: WKS B7_治具室CNC監控系統報警
  let body = {
    "site": 'WKS',
    "Plant": 'WKS',
    "eventId": 'FRCNC001',
    "eventType": '0',
    "syncId": '',
    "alertType": 0,
    "alertItem": 1,
    "issueType": 0,
    "uId": '',
    "status": 0,
    "level": 'L4',
    "shortMessage": '',
    "eventTime": '',
    "evtvalue1": 'WKS',  // 厂别
    "evtvalue2": 'null', // 线别
    "evtvalue3": '',     // 机种
    "evtvalue4": '',     // 设备名称
    "evtvalue5": '',     // 设备编号
    "evtvalue6": '',     // 故障描述
    "evtvalue7": '',     // 故障时间
    "evtvalue8": '10min',
    "pic": '',
    "mPic": '',
    "mPicPhone": '',
    "userId": '',
    "actionId": '',
    "comment": '',
    "extendDate": '',
    "replyUserId": '',
    "replyUserName": '',
    "replyDate": '',
    "toDMC": 1,
    "toNotify": 1
  };

  let date = new Date();
  body["level"] = level;
  body["syncId"] = g_cncInfo[index].name;
  body["eventTime"] = date.getTime().toString();
  body["evtvalue3"] = g_cncInfo[index].MachineModel;
  body["evtvalue4"] = g_cncInfo[index].MachineName;
  body["evtvalue5"] = g_cncInfo[index].MachineNO;
  body["evtvalue6"] = msg;
  body["evtvalue7"] = time;
  body["shortMessage"] = body["evtvalue1"] + '報警，线别：null，機種：' + body["evtvalue3"] + '，設備：' + body["evtvalue4"] + '，設備編號：' + body["evtvalue5"] + '，故障描述：' + body["evtvalue6"];

  try {
    let data = JSON.stringify(body);
    await sendHttpRequest(db_util.config.wx_url, data);
    let currentTime = getMonthDayTime(date, 1, 1);
    console.log('alarm: ' + g_cncInfo[index].MachineName + ' ' + msg + ' ' + level + ' on ' + currentTime);

    body["alertType"] = 1; // 事件状态，0/事件持续中；1/事件结束
    let json = {};
    json['eventTime'] = body["eventTime"];
    json['index'] = index;
    json['level'] = level;
    json['name'] = name;
    json['time'] = time;
    json['msg'] = msg;
    data = JSON.stringify(json);
    let sql = "select remark from cncother where name = '" + name + "'";
    let suc = await db_util.query(sql);
    if (suc.length == 0) {
      sql = "insert into cncother values('" + name + "', '" + data + "', '1', '" + body["eventTime"] + "', '" + currentTime + "')";
    }
    else {
      let count = parseInt(suc[0].remark);
      if (isNaN(count))
        count = 1;
      count++;
      sql = "update cncother set value = '" + data + "', remark = '" + count + "', other = '" + currentTime + "' where name = '" + name + "'";
    }
    await db_util.query(sql);
    if (suc.length == 0) // 加到报警记录表中
    {
      sql = "insert into cncalarm (name, MachineName, Time, alarmMsg, alarmTime) values('" + name + "', '" + g_cncInfo[index].MachineName + "', '" + body["eventTime"] + "', '" + msg + "', '" + time + "')";
      await db_util.query(sql);
    }
  }
  catch (error) {
    console.log(msg + ' ' + name + ' on ' + time + ' 异常：' + error.message);
  }
}

async function execute_http_request_datastream(msg, level, time, name) {
  //定义消息body eventName: WKS B7_治具室CNC監控系統報警
  let body = {
    "site": 'WKS',
    "Plant": 'WKS',
    "eventId": 'FRCNC001',
    "eventType": '0',
    "syncId": '',
    "alertType": 0,
    "alertItem": 1,
    "issueType": 0,
    "uId": '',
    "status": 0,
    "level": 'L4',
    "shortMessage": '',
    "eventTime": '',
    "evtvalue1": 'WKS',  // 厂别
    "evtvalue2": 'null', // 线别
    "evtvalue3": '',     // 机种
    "evtvalue4": '',     // 设备名称
    "evtvalue5": '',     // 设备编号
    "evtvalue6": '',     // 故障描述
    "evtvalue7": '',     // 故障时间
    "evtvalue8": '3min',
    "pic": '',
    "mPic": '',
    "mPicPhone": '',
    "userId": '',
    "actionId": '',
    "comment": '',
    "extendDate": '',
    "replyUserId": '',
    "replyUserName": '',
    "replyDate": '',
    "toDMC": 1,
    "toNotify": 1
  };

  let date = new Date();
  body["level"] = level;
  body["syncId"] = "CNC监控系统数据流监控";
  body["eventTime"] = date.getTime().toString();
  body["evtvalue3"] = "null";
  body["evtvalue4"] = "CNC监控系统数据流监控";
  body["evtvalue5"] = "null";
  body["evtvalue6"] = msg;
  body["evtvalue7"] = time;
  body["shortMessage"] = body["evtvalue1"] + '報警，线别：null，機種：' + body["evtvalue3"] + '，設備：' + body["evtvalue4"] + '，設備編號：' + body["evtvalue5"] + '，故障描述：' + body["evtvalue6"];

  try {
    let data = JSON.stringify(body);
    await sendHttpRequest(db_util.config.wx_url, data);
    let currentTime = getMonthDayTime(date, 1, 1);
    console.log('alarm: 数据流监控', msg, level, 'on', currentTime);

    body["alertType"] = 1;
    let json = {};
    json['eventTime'] = body["eventTime"];
    json['level'] = level;
    json['time'] = time;
    data = JSON.stringify(json);
    let sql = "select remark from cncother where name = '" + name + "'";
    let suc = await db_util.query(sql);
    let count = 0;
    if (suc.length == 0) {
      sql = "insert into cncother values('" + name + "', '" + data + "', '1', '" + body["eventTime"] + "', '" + currentTime + "')";
    }
    else {
      count = parseInt(suc[0].remark);
      if (isNaN(count))
        count = 0;
      count++;
      sql = "update cncother set value = '" + data + "', remark = '" + count + "', other = '" + currentTime + "' where name = '" + name + "'";
    }
    await db_util.query(sql);
    if (suc.length == 0 || count == 1) // 加到报警记录表中
    {
      sql = "insert into cncalarm (name, MachineName, Time, alarmMsg, alarmTime) values('" + name + "', '数据流监控', '" + body["eventTime"] + "', '" + msg + "', '" + time + "')";
      await db_util.query(sql);
    }
  }
  catch (error) {
    console.log('http request datastream error: ' + error.message);
  }
}

async function execute_http_request_2(data, msg) {
  try {
    let date = new Date();
    await sendHttpRequest(db_util.config.wx_url, data);
    console.log('alarm: ' + msg + ' on ' + getMonthDayTime(date, 1, 1));
  }
  catch (error) {
    console.log('http request 2 error: ' + error.message);
  }
}

async function execute_http_request_benefit_1(evt_dt, alarm_count, pay_hr) {
  let body = {
    "evt_dt": '',
    "freq": 'D',
    "site": 'WKS',
    "company": 'WSD',
    "plant": 'WKS-COMMON',
    "plant_code": 'WKS-COMMON',
    "system_id": 'smtcnc',
    "type_id": 'equipment_maintenanc',
    "benefit_type": 'direct',
    "params": [
      {
        "name": 'alarm_count',
        "value": 0,
        "type": 'VAR'
      },
      {
        "name": 'repair_time',
        "value": 0.02,
        "type": 'CONST'
      },
      {
        "name": 'dl_pay_hr',
        "value": 0,
        "type": 'VAR'
      }
    ]
  };
  body["evt_dt"] = evt_dt;
  body["params"][0].value = alarm_count;
  body["params"][2].value = pay_hr;

  try {
    let data = JSON.stringify(body);
    let ret = await sendHttpRequest(db_util.config.qas_url, data);
    let json = JSON.parse(ret);
    if (json["status"] == 200) {
      console.log('###### 设备维修对接效益平台 OK：' + JSON.stringify(json) + '，效益：' + alarm_count + ' x ' + pay_hr);
      return "ok";
    }
    else {
      console.log('###### 设备维修对接效益平台 报错：' + json["errors"]);
      return json;
    }
  }
  catch (error) {
    console.log('###### 设备维修对接效益平台 出错: ' + error.message);
    return error.message;
  }
}

async function execute_http_request_benefit_2(evt_dt, download_count, pay_hr) {
  let body = {
    "evt_dt": '',
    "freq": 'D',
    "site": 'WKS',
    "company": 'WSD',
    "plant": 'WKS-COMMON',
    "plant_code": 'WKS-COMMON',
    "system_id": 'smtcnc',
    "type_id": 'report_time',
    "benefit_type": 'direct',
    "params": [
      {
        "name": 'download_count',
        "value": 0,
        "type": 'VAR'
      },
      {
        "name": 'report_time',
        "value": 1,
        "type": 'CONST'
      },
      {
        "name": 'idl_pay_hr',
        "value": 0,
        "type": 'VAR'
      }
    ]
  };
  body["evt_dt"] = evt_dt;
  body["params"][0].value = download_count;
  body["params"][2].value = pay_hr;

  try {
    let data = JSON.stringify(body);
    let ret = await sendHttpRequest(db_util.config.qas_url, data);
    let json = JSON.parse(ret);
    if (json["status"] == 200) {
      console.log('###### 制作报表时间对接效益平台 OK' + '，效益：' + download_count + ' x ' + pay_hr);
      return "ok";
    }
    else {
      console.log('###### 制作报表时间对接效益平台 报错：' + json["errors"]);
      return json;
    }
  }
  catch (error) {
    console.log('###### 制作报表时间接效益平台 出错: ' + error.message);
    return error.message;
  }
}

async function execute_http_request_benefit_3(evt_dt, receive_count, pay_hr) {
  let body = {
    "evt_dt": '',
    "freq": 'D',
    "site": 'WKS',
    "company": 'WSD',
    "plant": 'WKS-COMMON',
    "plant_code": 'WKS-COMMON',
    "system_id": 'fsms',
    "type_id": 'cost_dl_receive',
    "benefit_type": 'direct',
    "params": [
      {
        "name": 'receive_count',
        "value": 0,
        "type": 'VAR'
      },
      {
        "name": 'receive_saving_time',
        "value": 10,
        "type": 'CONST'
      },
      {
        "name": 'dl_pay_hr',
        "value": 0,
        "type": 'VAR'
      }
    ]
  };
  body["evt_dt"] = evt_dt;
  body["params"][0].value = receive_count;
  body["params"][2].value = pay_hr;

  try {
    let data = JSON.stringify(body);
    let ret = await sendHttpRequest(db_util.config.qas_url, data);
    let json = JSON.parse(ret);
    if (json["status"] == 200) {
      console.log('###### 节约接单时间对接效益平台 OK' + '，效益：' + receive_count + ' x ' + pay_hr);
      return "ok";
    }
    else {
      console.log('###### 节约接单时间对接效益平台 报错：' + json["errors"]);
      return json;
    }
  }
  catch (error) {
    console.log('###### 节约接单时间接效益平台 出错: ' + error.message);
    return error.message;
  }
}

async function execute_http_request_benefit_4(evt_dt, download_count, pay_hr) {
  let body = {
    "evt_dt": '',
    "freq": 'D',
    "site": 'WKS',
    "company": 'WSD',
    "plant": 'WKS-COMMON',
    "plant_code": 'WKS-COMMON',
    "system_id": 'fsms',
    "type_id": 'cost_idl_download',
    "benefit_type": 'direct',
    "params": [
      {
        "name": 'download_count_check',
        "value": 0,
        "type": 'VAR'
      },
      {
        "name": 'report_time_save',
        "value": 1,
        "type": 'CONST'
      },
      {
        "name": 'idl_pay_hr',
        "value": 0,
        "type": 'VAR'
      }
    ]
  };
  body["evt_dt"] = evt_dt;
  body["params"][0].value = download_count;
  body["params"][2].value = pay_hr;

  try {
    let data = JSON.stringify(body);
    let ret = await sendHttpRequest(db_util.config.qas_url, data);
    let json = JSON.parse(ret);
    if (json["status"] == 200) {
      console.log('###### 制作报表时间对接效益平台 OK' + '，效益：' + download_count + ' x ' + pay_hr);
      return "ok";
    }
    else {
      console.log('###### 制作报表时间对接效益平台 报错：' + json["errors"]);
      return json;
    }
  }
  catch (error) {
    console.log('###### 制作报表时间接效益平台 出错: ' + error.message);
    return error.message;
  }
}

let benefit_get_laborcost = function (type) {
  return new Promise((resolve, reject) => {
    let url = db_util.config.benefit_api + "/api/BenefitLaborCosts/latestCost?site=wks&plant=wks-common&type=" + type;
    request(url, function (err, response, body) {
      if (err) {
        //reject(err);
        console.log(err.message);
        let json = {};
        json["type"] = type;
        if (type == "DL")
          json['cost'] = 21;
        else
          json['cost'] = 29.4;
        resolve(json);
      }
      else {
        try {
          let json = JSON.parse(body);
          json['cost'] = dotFixed(json['cost']);
          resolve(json);
        }
        catch (error) {
          console.log(error.message, body);
          let json = {};
          json["type"] = type;
          if (type == "DL")
            json['cost'] = 21;
          else
            json['cost'] = 29.4;
          resolve(json);
        }
      }
    });
  });
}

let query_qiyeweixin_huifu = function (starttime, endtime) {
  return new Promise((resolve, reject) => {
    let url = db_util.config.dmc_api + "?filter[where][STime][between][0]=" + starttime;
    url += "&filter[where][STime][between][1]=" + endtime + "&filter[where][toDMC]=1&filter[where][System]=wks&filter[where][eventId]=FRCNC001";
    request(url, function (err, response, body) {
      if (err) {
        reject(err);
      }
      else {
        resolve(body);
      }
    });
  });
}

async function addAlarmCount(alarm_count) {
  let sql = "";
  let ret = await db_util.query("select * from cncother where name = 'alarmcount'");
  if (ret.length > 0) {
    let count = parseInt(ret[0].value);
    if (isNaN(count))
      count = 0;
    alarm_count += count;
  }
  if (ret.length == 0)
    sql = "insert into cncother (name, value) values('alarmcount', '" + alarm_count + "')";
  else
    sql = "update cncother set value = '" + alarm_count + "' where name = 'alarmcount'";
  await db_util.query(sql);
}

async function intervalAlarm() {
  let date = new Date();
  let hour = date.getHours();
  // 对接效益平台
  try {
    if (hour >= 0 && hour < 1 && date.getMinutes() < 10) {
      let check = false;
      let riqi = getMonthDayTime(date, 1);
      let xiaoyipingtai = await db_util.query("select * from cncother where name = 'xiaoyipingtai'");
      if (xiaoyipingtai.length == 0)
        check = true;
      else if (xiaoyipingtai[0].value != riqi)
        check = true;
      if (check == true) {
        let cost_DL = await benefit_get_laborcost('DL');
        let cost_IDL = await benefit_get_laborcost('IDL');
        console.log(getMonthDayTime(date, 1, 1) + ': query loborcost, DL - ' + cost_DL["cost"] + ', IDL - ' + cost_IDL["cost"]);

        let alarm_count = 0;
        let alct = await db_util.query("select * from cncother where name = 'alarmcount'");
        if (alct.length > 0) {
          alarm_count = parseInt(alct[0].value);
          if (isNaN(alarm_count))
            alarm_count = 0;
        }
        let dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
        let evt_dt = dt.getTime() - 24 * 3600 * 1000;
        let alarm_ret = await execute_http_request_benefit_1(evt_dt, alarm_count, cost_DL["cost"]);

        alarm_count = 0;
        let dload = await db_util.query("select * from cncother where name = 'downloadcount'");
        if (dload.length > 0) {
          alarm_count = parseInt(dload[0].value);
          if (isNaN(alarm_count))
            alarm_count = 0;
        }
        let download_ret = await execute_http_request_benefit_2(evt_dt, alarm_count, cost_IDL["cost"]);

        let sql = "";
        if (alarm_ret == 'ok' && download_ret == 'ok') {
          if (xiaoyipingtai.length == 0)
            sql = "insert into cncother (name, value) values('xiaoyipingtai', '" + riqi + "')";
          else
            sql = "update cncother set value = '" + riqi + "' where name = 'xiaoyipingtai'";
          await db_util.query(sql);
        }
        if (alarm_ret == 'ok') {
          sql = "update cncother set value = '0' where name = 'alarmcount'";
          await db_util.query(sql);
        }
        if (download_ret == 'ok') {
          sql = "update cncother set value = '0' where name = 'downloadcount'";
          await db_util.query(sql);
        }
      }
    }
  }
  catch (error) {
    console.log('对接效益平台 error: ' + error.message + ' on ' + getMonthDayTime(date, 1, 1));
  }

  // 查询企业微信回复
  try {
    let endtime = date.getTime();
    let i = endtime - 7 * 24 * 3600 * 1000;
    let sql = "select id, name, MachineName, Time from cncalarm where reason = '' and Time > '" + i + "'";
    let suc = await db_util.query(sql);
    if (suc.length > 0) {
      let starttime = parseInt(suc[0].Time);
      let ret = await query_qiyeweixin_huifu(starttime, endtime);
      let objs = eval(ret);
      for (i = 0; i < objs.length; i++) {
        if (objs[i].reason.length == 0)
          continue;
        for (let k = 0; k < suc.length; k++) {
          if (suc[k].Time == objs[i]["eventTime"]) {
            sql = "update cncalarm set reason = '" + objs[i]["reason"] + "', pic = '" + objs[i]["pic"] + "', replyDate = '" + objs[i]["replyDate"] + "' where id = '" + suc[k].id + "'";
            await db_util.query(sql);

            // 解除报警
            sql = "select * from cncother where name = '" + suc[k].name + "'";
            let suc2 = await db_util.query(sql);
            if (suc2.length > 0) {
              let msg = suc[k].MachineName + " 警报解除";
              await execute_http_request_2(suc2[0].value, msg);
              console.log(msg + ' 来自企业微信回复：' + objs[i].reason);
              sql = "delete from cncother where name = '" + suc[k].name + "'";
              await db_util.query(sql);

              let alarm_time = parseInt(suc2[0].reserved); // 第一次报警的时间，同时作为cncalarm表中的记录识别标记
              msg = getMonthDayTime(date, 1, 1) + " 警报解除 企业微信回复：见reason栏位";
              sql = "update cncalarm set status = '" + msg + "' where Time = '" + alarm_time + "'";
              await db_util.query(sql);

              // 报警次数加1
              let alarm_count = 1;
              await addAlarmCount(alarm_count);
            }
            break;
          }
        }
      }
    }
  }
  catch (error) {
    console.log('查询企业微信回复 error: ' + error.message + ' on ' + getMonthDayTime(date, 1, 1));
  }

  let isIdle = await isIdleTime(date);
  if (isIdle)
    return;

  // 每个整点时间点检查上一个小时的单台设备稼动率/OEE是否低于目标值
  if (date.getMinutes() < 10) {
    let check = false;
    let alarmtime = await db_util.query("select * from cncother where name = 'alarmtime'");
    if (alarmtime.length == 0)
      check = true;
    else if (parseInt(alarmtime[0].value) != hour)
      check = true;
    if (check == true) {
      let sql = "";
      if (alarmtime.length == 0)
        sql = "insert into cncother (name, value) values('alarmtime', '" + hour + "')";
      else
        sql = "update cncother set value = '" + hour + "' where name = 'alarmtime'";
      await db_util.query(sql);

      let dt = new Date(date.getFullYear(), date.getMonth(), date.getDate(), hour);
      let st = new Date(dt.getTime() - 3600 * 1000);
      let starttime = getMonthDayTime(st, 1, 1);
      let endtime = getMonthDayTime(dt, 1, 1);
      //console.log('检查上一个小时的单台设备稼动率 ' + getMonthDayTime(date, 1, 1));
      let rows = await StatisticUtilization(undefined, starttime, endtime);
      let target = await db_util.query("select * from cncother where name = 'jiadonglvValue'");
      let value = 80;
      if (target.length > 0)
        value = parseInt(target[0].value);
      let alarm_count = 0;
      for (let i = 0; i < rows.length; i++) {
        if (rows[i].total_time < 1)
          continue;
        if ((rows[i].total_time - rows[i].off_time) < 1000) // 关机了，不用报警
        {
          console.log(rows[i].MachineName + ' 关机了');
          continue;
        }
        let jiadonglv = parseInt(rows[i].run_time / (rows[i].total_time / 100));
        if (isNaN(jiadonglv)) {
          console.log(rows[i].MachineName + '稼动率计算异常！total_time = ' + rows[i].total_time);
          jiadonglv = value;
        }
        console.log(rows[i].MachineName + '稼动率：' + jiadonglv);
        let name = "alarm-" + g_cncInfo[i].MachineName;
        if (jiadonglv < value) {
          alarm_count++;
          let level = 'L4';
          sql = "select remark from cncother where name = '" + name + "'";
          let suc = await db_util.query(sql);
          if (suc.length > 0) {
            let count = parseInt(suc[0].remark);
            if (isNaN(count))
              count = 1;
            if (count >= 3)
              level = 'L1';
            else if (count == 2)
              level = 'L2';
            else
              level = 'L3';
          }
          await execute_http_request(i, "稼动率低于标准值", level, starttime, name); // 要确保cncalarm中每条记录的Time都不一样
        }
        else {
          sql = "select * from cncother where name = '" + name + "'";
          let suc = await db_util.query(sql);
          if (suc.length > 0) {
            alarm_count++;
            let alarm_time = suc[0].reserved;
            let msg = g_cncInfo[i].MachineName + " 警报解除";
            await execute_http_request_2(suc[0].value, msg);

            sql = "delete from cncother where name = '" + name + "'";
            await db_util.query(sql);

            msg = getMonthDayTime(date, 1, 1) + " 警报解除";
            sql = "update cncalarm set status = '" + msg + "' where Time = '" + alarm_time + "'";
            await db_util.query(sql);
          }
        }
      }
      if (alarm_count > 0) {
        await addAlarmCount(alarm_count);
      }
    }
  }
}

async function isIdleTime(date) {
  let hour = date.getHours();
  let currTime = date.getTime();
  let suc3 = await db_util.query("select * from cnctime");
  for (let i = 0; i < suc3.length; i++) {
    let st = parseInt(suc3[i].starttime);
    let et = parseInt(suc3[i].endtime);
    if (suc3[i].starttime.indexOf('-') > 0)
      st = Date.parse(suc3[i].starttime);
    if (suc3[i].endtime.indexOf('-') > 0)
      et = Date.parse(suc3[i].endtime);
    if (currTime >= st && currTime < et) {
      if (suc3[i].status == "0") // 休假
      {
        return true;
      }
      else {
        return false;
      }
    }
  }
  //if( (currTime - g_lastUpdateTime) < g_nWaitTime ) // 周日还在加班，但没有设置
  //  return false; // 2021-10-26修改，除非把周日设置成加班才会检查是否触发微信报警条件
  if (date.getDay() == 0 && hour >= 8)
    return true;
  if (date.getDay() == 1 && hour < 8)
    return true;
  return false;
}

async function intervalMonitorDataStream() {
  let date = new Date();
  let name = 'datastream';
  let currTime = date.getTime();
  let time = currTime - g_lastUpdateTime;
  let suc = await db_util.query("select * from cncother where name = '" + name + "'");
  if (time < g_nWaitTime) {
    if (suc.length == 0)
      return;
    let msg = "CNC监控系统数据流中断 警报解除";
    await execute_http_request_2(suc[0].value, msg);
    sql = "delete from cncother where name = '" + name + "'";
    await db_util.query(sql);

    let alarm_time = parseInt(suc[0].reserved); // 第一次报警的时间，同时作为cncalarm表中的记录识别标记
    msg = getMonthDayTime(date, 1, 1) + " 警报解除";
    sql = "update cncalarm set status = '" + msg + "' where Time = '" + alarm_time + "'";
    await db_util.query(sql);

    // 报警次数加1
    let alarm_count = 1;
    await addAlarmCount(alarm_count);
    return;
  }
  let isIdle = await isIdleTime(date);
  if (isIdle)
    return;
  let level = 'L4';
  let starttime = getMonthDayTime(date, 1, 1);
  if (suc.length == 0) {
    let json = {};
    json['eventTime'] = currTime;
    let data = JSON.stringify(json);
    sql = "insert into cncother values('" + name + "', '" + data + "', '0', '" + currTime + "', '" + starttime + "')";
    await db_util.query(sql);
    return;
  }
  else {
    let count = parseInt(suc[0].remark);
    if (isNaN(count))
      count = 0;
    let last_send_time = parseInt(suc[0]['reserved']);
    if (isNaN(last_send_time))
      last_send_time = currTime;
    let wait_time = 5 * 60 * 1000;
    if (count == 1)
      wait_time = 25 * 60 * 1000;
    else if (count == 2)
      wait_time = 45 * 60 * 1000;
    else if (count == 3)
      wait_time = 60 * 60 * 1000;
    else if (count >= 4) {
      wait_time = 180 * 60 * 1000;
      let obj = JSON.parse(suc[0].value);
      last_send_time = parseInt(obj.eventTime);
    }
    if ((currTime - last_send_time) < wait_time) {
      return;
    }
    if (count >= 4) {
      last_send_time = currTime - parseInt(suc[0]['reserved']);
      wait_time = parseInt(last_send_time / 60000);
      let hours = parseInt(wait_time / 60);
      let minutes = wait_time - hours * 60;
      level = 'CNC监控系统数据流持续中断' + hours + '小时';
      if (minutes > 0)
        level += minutes + '分钟';
      level += '。。。。。。' + starttime;
      console.log(level);

      count++;
      let obj = JSON.parse(suc[0].value);
      obj['eventTime'] = currTime;
      let data = JSON.stringify(obj);
      sql = "update cncother set value = '" + data + "', remark = '" + count + "' where name = '" + name + "'";
      await db_util.query(sql);
      return;
    }
    if (count >= 3)
      level = 'L1';
    else if (count == 2)
      level = 'L2';
    else if (count == 1)
      level = 'L3';
  }
  await execute_http_request_datastream("CNC监控系统数据流中断", level, starttime, name);
}

async function intervalHealthReportCNC() {
  let date = new Date();
  let body = {
    "plant": 'WKS',
    "systemid": 'smtcnc',
    "todsm": 0,
    "tosumk": 0,
    "tobenefit": 0,
    "todmc": 0,
    "systemversion": "20210531.027",
    "uploadtime": 0
  };
  let body1 = {
    "plant": 'WKS',
    "systemid": 'smtcnc',
    "datas": [
      {
        "datatype": '稼动率',
        "devicename": '0', // 装置名称
        "deviceid": '0',   // 装置编号
        "event_time": '0', // 发生时间
        "actualdata": '0', // 数值
        "datarange": '0-100' // 数值范围
      }
    ],
    "uploadtime": 0
  };
  let body2 = {
    "plant": 'WKS',
    "systemid": 'smtcnc',
    "datadate": '',
    "actual": '',
    "target": '1',
    "status": '1',
    "cmpunitdesc": '网页浏览次数',
    "uploadtime": 0
  };
  body["uploadtime"] = date.getTime();
  body1["uploadtime"] = date.getTime();
  body2["uploadtime"] = date.getTime();
  date.setTime(body2["uploadtime"] - 24 * 3600 * 1000);
  body2["datadate"] = getMonthDayTime(date, 1);
  date.setTime(body2["uploadtime"]);
  body1["datas"]["event_time"] = date.getTime().toString();

  //let currentTime = getMonthDayTime(date, 1, 1);

  try {
    setTime(date, 0, 0, 0);
    let temp = getMonthDayTime(date, 1, 1);
    let sql = "select * from workhour where keypoint >= '" + temp + "'";
    let suc = await db_util.query(sql);
    body2["actual"] = suc.length.toString();

    //console.log('平台心跳上抛 on ' + currentTime);
    let data = JSON.stringify(body);
    await sendHttpRequest(db_util.config.ptxt_url, data);

    temp = getMonthDayTime(date);
    sql = "select * from currentmonth where month = '" + temp + "' and MachineName = 'total'";
    /*let succ2 = await db_util.query(sql);
    if( succ2.length > 0 )
    {
      let run_time = parseInt(succ2[0]["run_time"]);
      let total_time = parseInt(succ2[0]["total_time"]);
      if( isNaN(total_time) )
        total_time = 0;
      if( total_time > 0 )
        body1["datas"]["actualdata"] = parseInt(100*run_time/total_time).toString();
    }
    else
    {
      console.log(currentTime + ' CNC health report, no data of month ' + temp);
    }
    //console.log('健康状况上抛 on ' + currentTime);
    data = JSON.stringify(body1);
    await sendHttpRequest(db_util.config.jksy_url, data);*/

    //console.log('使用状况上抛 on ' + currentTime);
    data = JSON.stringify(body2);
    await sendHttpRequest(db_util.config.sylv_url, data);
  }
  catch (error) {
    console.log('HealthReport 异常：' + error.message);
  }
}

async function intervalHealthReportFSMS(dateNew) {
  let date = new Date();
  if (dateNew != undefined) {
    let k = Date.parse(dateNew);
    if (isNaN(k) == false) {
      date.setTime(k);
    }
  }
  let body = {
    "plant": 'WKS',
    "systemid": 'FSMS',
    "todsm": 0,
    "tosumk": 0,
    "tobenefit": 0,
    "todmc": 0,
    "systemversion": "20210531.027",
    "uploadtime": 0
  };
  let body2 = {
    "plant": 'WKS',
    "systemid": 'FSMS',
    "datadate": '09-23',
    "actual": '',
    "target": '2',
    "status": '1',
    "cmpunitdesc": '訂單結案率',
    "uploadtime": 0
  };
  body["uploadtime"] = date.getTime();
  body2["uploadtime"] = date.getTime();
  body2["datadate"] = getMonthDayTime(date, 1);

  try {
    let currTime = getMonthDayTime(date, 1, 1);
    let data = JSON.stringify(body);
    if (dateNew == undefined) {
      console.log('平台心跳上抛 on ' + currTime);
      await sendHttpRequest(db_util.config.ptxt_url, data);
    }

    let hour = date.getHours();
    if (hour >= 0 && hour < 4) {
      setTime(date, 0, 0, 0);
      let riqi = getMonthDayTime(date, 1);
      let check = false;
      let jieanlv = await db_util.query("select * from cncother where name = 'jieanlv'");
      if (jieanlv.length == 0)
        check = true;
      else if (jieanlv[0].value != riqi)
        check = true;
      if (check == true) {
        // 使用率
        let currentTime = date.getTime();
        let endtime = getMonthDayTime(date, 1, 1);
        date.setTime(currentTime - 24 * 3600 * 1000);
        body2["datadate"] = getMonthDayTime(date, 1);
        let starttime = getMonthDayTime(date, 1, 1);
        let sql = "select * from delivery_sheet where starttime >= '" + starttime + "' and starttime < '" + endtime + "'";
        //let succ2 = await db_util.query(sql); // 当天结案的数目
        sql = "select id, ActualCompleteDay from p79_tofsms where ActualCompleteDay >= '" + starttime + "' and ActualCompleteDay < '" + endtime + "'";
        let succ3 = await db_util.query(sql); // 当天的订单数目
        body2["actual"] = succ3.length.toString();
        if (succ3.length < 2) {
          body2["status"] = '0';
        }
        console.log('使用状况上抛 on ' + currTime);
        data = JSON.stringify(body2);
        await sendHttpRequest(db_util.config.sylv_url, data);

        if (jieanlv.length == 0)
          sql = "insert into cncother (name, value) values('jieanlv', '" + riqi + "')";
        else
          sql = "update cncother set value = '" + riqi + "' where name = 'jieanlv'";
        await db_util.query(sql);

        // 对接效益平台
        check = false;
        let xiaoyipingtai = await db_util.query("select * from cncother where name = 'fsmsxypt'");
        if (xiaoyipingtai.length == 0)
          check = true;
        else if (xiaoyipingtai[0].value != riqi)
          check = true;
        if (check == true) {
          date.setTime(currentTime);
          let cost_DL = await benefit_get_laborcost('DL');
          let cost_IDL = await benefit_get_laborcost('IDL');
          console.log(currTime + ': query loborcost, DL - ' + cost_DL["cost"] + ', IDL - ' + cost_IDL["cost"]);

          let alarm_count = succ3.length;
          let evt_dt = currentTime - 24 * 3600 * 1000;
          let alarm_ret = await execute_http_request_benefit_3(evt_dt, alarm_count, cost_DL["cost"]);

          alarm_count = 0;
          let dload = await db_util.query("select * from cncother where name = 'downloadcount'");
          if (dload.length > 0) {
            alarm_count = parseInt(dload[0].value);
            if (isNaN(alarm_count))
              alarm_count = 0;
          }
          let download_ret = await execute_http_request_benefit_4(evt_dt, alarm_count, cost_IDL["cost"]);

          let sql = "";
          if (alarm_ret == 'ok' && download_ret == 'ok') {
            if (xiaoyipingtai.length == 0)
              sql = "insert into cncother (name, value) values('fsmsxypt', '" + riqi + "')";
            else
              sql = "update cncother set value = '" + riqi + "' where name = 'fsmsxypt'";
            await db_util.query(sql);
          }
          if (download_ret == 'ok' && dload.length > 0) {
            sql = "update cncother set value = '0' where name = 'downloadcount'";
            await db_util.query(sql);
          }
        }
      }
    }
  }
  catch (error) {
    console.log('FSMS HealthReport 异常：' + error.message);
  }

  if (dateNew == undefined) {
    await intervalHealthReportCNC();
  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
process.on('uncaughtException', (reason, p) => {
  var date = new Date();
  console.log('系统捕获异常: ', getMonthDayTime(date, 1, 1), ', at ', p, ', ', reason);
});


//配置服务端口。如果没有指定hostname，这个服务器会接收任何ipv6主机的访问，否则使用ipv4。
//所以当只需要获取远程客户端的ip时，需要指定hostname参数为0.0.0.0。
var server = app.listen(3000, '0.0.0.0', function () {
  //let host = server.address().address;
  let port = server.address().port;
  let date = new Date();

  console.log(getMonthDayTime(date, 1, 1));
  console.log(db_util.config.db_name + ' api listening port %s', port);

  httpServer.listen(3001);

  g_cncOeeMonthBusy = false;
  g_nWaitTime = 180 * 1000; // 最大等待时间：3分钟
  g_nOffTime = 600 * 1000;  // 最小关机时间间隔：10分钟
  g_lastUpdateTime = date.getTime() - g_nWaitTime * 2;
  setTimeout(function () { setInterval(intervalMonitorDataStream, 60000); }, (g_nWaitTime + 60 * 1000));
  loadCNC();
  setInterval(intervalFunc, 299890); // 间隔5分钟左右
  // setInterval(intervalAlarm, 149830); // 间隔2分半左右  delete by sam shen
  // setInterval(intervalHealthReportFSMS, 600130);       delete by sam shen
  setTimeout(function () { kafkaTest(); }, 1000);
})

module.exports = app;